mixmaster

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

commit 50de79fe7f9e194b5a6bdd3a63fb3bdb455588a8
Author: parazyd <parazyd@dyne.org>
Date:   Thu, 15 Sep 2016 01:44:49 +0200

initial sources import

Diffstat:
ABUILD.Win32 | 30++++++++++++++++++++++++++++++
ACOPYRIGHT | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AHISTORY | 502+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AInstall | 1403+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/Makefile.deps | 46++++++++++++++++++++++++++++++++++++++++++++++
ASrc/Makefile.in | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/buffers.c | 816+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/chain.c | 384+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/chain1.c | 301+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/chain2.c | 685+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/compress.c | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/config.h | 403+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/crypto.c | 492+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/crypto.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/dllmain.c | 35+++++++++++++++++++++++++++++++++++
ASrc/dummy.c | 16++++++++++++++++
ASrc/keymgt.c | 434+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/mail.c | 898+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/maildir.c | 323+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/main.c | 820+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/menu.c | 1003+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/menu.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/menunym.c | 472+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/menusend.c | 556+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/menustats.c | 445+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/menuutil.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/mime.c | 814+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/mix.c | 1262+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/mix.h | 917+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/mix3.h | 443+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/mixlib.def | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/mpgp.c | 264+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/nym.c | 669+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/parsedate.y | 879+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/pgp.c | 494+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/pgp.h | 189+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/pgpcreat.c | 848+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/pgpdata.c | 1539+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/pgpdb.c | 583+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/pgpget.c | 870+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/pool.c | 981+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/random.c | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/rem.c | 709+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/rem1.c | 599+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/rem2.c | 486+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/remailer.c | 36++++++++++++++++++++++++++++++++++++
ASrc/rfc822.c | 585+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/rndseed.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/service.c | 331+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/stats.c | 442+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/tests/test-parse_yearmonthday.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/util.c | 704+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASrc/version.h | 1+
ATHANKS | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ATODO | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/abuse.txt.in | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/adminkey.txt | 1+
Aconf/blocked.txt.in | 20++++++++++++++++++++
Aconf/dest.alw | 41+++++++++++++++++++++++++++++++++++++++++
Aconf/dest.blk | 2++
Aconf/end.hlp | 36++++++++++++++++++++++++++++++++++++
Aconf/header.blk | 22++++++++++++++++++++++
Aconf/intro.hlp | 15+++++++++++++++
Aconf/mix.cfg | 14++++++++++++++
Aconf/mix.cfg.ex | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/mix.hlp | 45+++++++++++++++++++++++++++++++++++++++++++++
Aconf/mlist.txt | 48++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/news.hlp | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/pgp.hlp | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/pgponly.hlp | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/pubring.asc | 544+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/pubring.mix | 384+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/rab.blk | 0
Aconf/reply.txt.in | 32++++++++++++++++++++++++++++++++
Aconf/rlist.txt | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/type1.hlp | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconf/usage.txt.in | 24++++++++++++++++++++++++
Aidea.txt | 34++++++++++++++++++++++++++++++++++
Amixmaster.1 | 1136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ampgp.1 | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/installer/mixinstall.nsi | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/mix.sln | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/mix.vcproj | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/mixlib.vcproj | 459+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/pcre.vcproj | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/pcre_chartables.vcproj | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/pdcurses.vcproj | 607+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awin32/zlib.vcproj | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
89 files changed, 31462 insertions(+), 0 deletions(-)

diff --git a/BUILD.Win32 b/BUILD.Win32 @@ -0,0 +1,30 @@ +Mixmaster on Windows is known to build with Microsoft Visual Studio .NET +2003 Professional. + +You will need openssl, zlib, pcre, and pdcurses. + +First, build openssl as described in the openssl documentation. Place +the entire build directory in Src/openssl. + +zlib, pcre, and pdcurses sources are assumed to be in Src/zlib-1.1.4, +Src/pcre-2.08, and Src/pdcurses respectively. + +Open the mixmaster project win32/mix.sln, and build the mix solution. +You should find the results in win32/release. + + +References: + - http://www.openssl.org/ + - http://pdcurses.sourceforge.net/ + +-- +Peter Palfrader, Sat, 1 May 2004 20:31:48 +0200 + + +[Note to users of Mixmaster 3.0rc1 and earlier: mix.cfg.txt and pop3.cfg +are now named mix.ini and pop3.ini, respectively, on WIN32. You will +need to manually rename your custom config files, if appropriate.] + +-- +Len Sassaman, Thu, 13 Sep 2007 14:56:37 +0200 + diff --git a/COPYRIGHT b/COPYRIGHT @@ -0,0 +1,134 @@ +Copyright (c) 1999-2000 Anonymizer Inc. +Copyright (c) 2000-2002 Ulf Moeller +Copyright (c) 2001-2002 Janis Jagars +Copyright (c) 2001-2007 Peter Palfrader +Copyright (c) 2001-2008 Len Sassaman +Copyright (c) 2004-2008 Colin Tuckley +Copyright (c) 2007-2008 Steve Crook + + +MIXMASTER LICENSE AGREEMENT + +1. Grant of License. + + Anonymizer Inc. grants you the following non-exclusive license for + the Mixmaster program and its associated documentation (the "Program"), + subject to all of the following terms and conditions: + + a) You may use the Program, and copy and distribute verbatim copies + of the Program as you receive it, in any medium. + + Local regulations may exist which limit your rights to distribute or + use cryptographic software. In certain jurisdictions, parts of this + software may be protected by patents. It is your responsibility to + obtain the appropriate licenses. + + b) You may modify the Program or incorporate the Program or any + portion of it into other computer programs. You may copy and + distribute such modifications or work, provided that you: + + (i) cause the modified Program to carry a prominent notice + stating that it has been modified, and cause the modified files + to carry notices stating that you changed the files and the + date of any change; + + (ii) reproduce and include this Agreement, the copyright + notices and disclaimer of warranty on any copy; and + + (iii) provide Anonymizer Inc. with a copy of the Source Code of + such modifications or work via electronic mail to the address + mixmaster@anonymizer.com, and grant Anonymizer Inc. a perpetual, + royalty-free license to use and distribute the modifications or + work in its products. + + "Source Code" means the preferred form of a work for making + modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to + control compilation and installation of an executable. + + c) Should Anonymizer Inc. be acquired by another entity, you: + + (i) will grant to the acquiring entity the items in section + 1.b.(iii) in leiu of Anonymizer, Inc.; + + d) Should Anonymizer Inc. cease to exist, and no aquiring entity be + available to accept Source Code modifications, you: + + (i) will grant Lance Cottrell the items in section 1.b.(iii) in leiu + of Anonymizer, Inc. + + (ii) should Mr. Cottrell be deceased, section 1.b.(iii) of this + license will be rendered null and void. + + e) In the case that the electronic mail address mixmaster@anonymizer.com + ceases to accept electronic mail, + + (i) submission of changes to the Mixmaster project at SourceForge + will be accceptable; + + (ii) if Mixmaster development is no longer hosted by SourceForge, + submission of changes to any open source repository similar to + SourceForge, or + + (iii) submission to the Internet news group alt.privacy.anon-server + will be acceptable. + + f) Submission of changes is required as a "best effort". If it is not + possible for you to access any of the notification locations, a notation + in the modified code stating that the modifications should be submitted by + any capable parties who subsequently make use of the modified code will + be acceptable in lieu of code submission. + +2. Reservation of Rights. + + No rights are granted to the Program except as expressly set forth + herein. You may not copy, modify, sublicense, or distribute the + Program except as expressly provided under this Agreement. Any + attempt otherwise to copy, modify, sublicense or distribute the + Program is void, and will automatically terminate your rights under + this Agreement. + +3. DISCLAIMER OF WARRANTY. + + BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. THE + PROGRAM IS PROVIDED ON AN ``AS IS'' BASIS, WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, + WARRANTIES THAT THE PROGRAM IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR + A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE + QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT ANONYMIZER INC. OR + ANY DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY + NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF + WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF THE + PROGRAM IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +4. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL ANONYMIZER INC. + OR ANY DEVELOPER OR ANY OTHER CONTRIBUTOR OR ANY SUPPLIER OF ANY OF + SUCH PARTIES, BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER + INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK + STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +5. General. + + This license represents the complete agreement concerning subject + matter hereof. If any provision of this Agreement is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This Agreement shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + The application of the United Nations Convention on Contracts for the + International Sale of Goods is expressly excluded. Any law or + regulation which provides that the language of a contract shall be + construed against the drafter shall not apply to this License. diff --git a/HISTORY b/HISTORY @@ -0,0 +1,502 @@ + 1998/1999 2.9 written from scratch. + +1999-04-14 2.9beta0 public preview release. + +1999-05-17 2.9beta1 Bug fixes (remix, OpenPGP encryption, FreeBSD + name conflict); Win32 DLL. + +1999-05-18 2.9beta2 Install bug fixes. -N and -n options renamed. + +1999-05-19 2.9beta3 OpenSSL-related bug fix. Type 1 remailer fixes + (pointed out by <kev@drule.org>). + +1999-05-20 2.9beta4 Read and generate OpenPGP encrypted secret keys. + +1999-05-20 2.9beta5 The client sent messages if PGP encryption failed. + +1999-05-28 2.9beta6 Message-ID generation bug fixes. Contributed by: + Johannes Kroeger <hanne@squirrel.owl.de>. + Remix-To bug fix. + +1999-06-09 2.9beta7 More (minor) remailer and Install script fixes. + +1999-06-10 2.9beta8 Regular expression bug fix. Thanks to Johannes + and Kevin for help with debugging! + +1999-07-20 2.9beta9 Bug fixes (remailer, nym creation). + +1999-08-03 2.9beta10 Fix for buffer overrun error. + "Chain:" pseudo-header may contain the number of + copies like this: `Chain: *,*,*,*; copies=3' + +1999-09-09 2.9beta11 Support MIME attachments and OpenPGP/MIME in the + client. + Do not select cpunk remailers if PGP key is missing. + Fix error in nym creation. + Header lines can be edited when composing new + messages in the mail reader. + Accept empty pass phrase to allow storing the + nym database on an encrypted file system. + More verbose error messages. + Various minor bug fixes. + * Thanks to Gerd Beuster for many good suggestions! + +1999-09-22 2.9beta12 OpenSSL 0.9.3 or newer is now required. + For the Mixmaster DLL, allow the application to + seed the random number generator. + +1999-09-29 2.9beta13 Fix OpenPGP 3DES decryption. + Store DSA secret keys in PGP5 compatible format. + Support new "ekx" capability. + Use the more secure new style OpenPGP conventional + encryption to protect the nym database and nym + keys. + +1999-10-01 2.9beta14 Bug fix. + +1999-10-01 2.9beta15 Bug fix: create mixrand.bin in Mix directory. + Support "Encrypt-IDEA" directive. + +1999-10-11 2.9beta16 Fix memory leaks. + +1999-11-03 2.9beta17 Bug fix. + Sending messages is logged as DEBUGINFO. + +1999-11-09 2.9beta18 Bug fix for rlist with trailing spaces. + Print remailer reliability (by Gerd Beuster). + +1999-12-19 2.9beta19 (internal) + +1999-12-19 2.9beta20 Output remailer RSA keys separately from the + DSA/ElGamal keys to avoid problems with old + versions of PGP. + Messages in mail folders can be deleted. Nym + messages and other encrypted mail will be + written back as plain text (by Gerd Beuster). + SMTP bug fix. + Support multiple OpenPGP decryption subkeys. + Fix remailer bug with Newsgroups header in encrypted + T1 messages. + Fix MIME-decoding bug (pointed out by Gerd Beuster). + Nym creation bug fix (by Gerd Beuster). + +2000-03-09 2.9beta21 Support for PGP partial length packets (by + Christian Mock). + +2000-03-16 2.9beta22 Bug fixes (by Antonomasia) and minor changes. + +2000-06-29 2.9beta23 Bug fix for nym creation with several newsgroups + reply blocks (by Gerd Beuster). + --nym option bug fix (by Adam Back). + +2001-09-11 2.9beta24 Changed pool.c to allow Mixmaster keys to pass + even when binary blocking is enabled. Note that + the solution is not a nice one: It does not + recognize Mix keys, it simply allows 10 lines of + binary garbage instead of 3. This should be enough + for Mix keys to come through (by Peter Palfrader). + Fixed a bug in pgpdata.c affecting v3 OpenPGP keys. + (by Michael Young). + +2001-09-14 2.9beta25 Now builds with pcre3 (by Peter Palfrader). + Added support for destination.allow (by Peter + Palfrader). + If the sender email address or IP address matches + anything in source.blk, ignore the message (by + cmeclax). + Added support for the Mutt -T option (by Bill + O'Hanlon). + Patches merged (by Len Sassaman). + +2001-09-17 2.9beta30 Version renamed to avoid conflicts with other + unofficial releases. + +2001-09-19 2.9beta31 Fixed a bug in mime.c that sometimes resulted in + malformed text attachments (by Michael Young). + Better error handling (by Scott Renfro). + Added support for multiple dest.blk files. This + is needed for the Remailer Abuse Blocklist (by + Markus Stöger). + Added support for remailer-adminkey replies to + provide a better way for remops to distribute + their keys. (by Markus Stöger). + Fixed errors with pcre2.08 (by Rodney Thayer). + Added long command option --type-list for the -T + option, and updated help (by Len Sassaman). + Removed redundant "encoded" variable in mime.c. + Fixed Installer bugs. + +2001-11-06 2.9beta32 Client functionality updates. + POP sockets now properly close. + Memory may be freed without allocating. + Correct time is written to mbox. + Key flags correctly set in key.txt. (all by + Disastry). + OpenSSL and OpenBSD Install script issues + addressed. + +2001-12-16 2.9b33 Support for Mixmaster as a service on Windows + platforms added (by Disastry). + Problem transparently remixing to Type I remailers + debugged and corrected (by Andy Dustman, + Disastry, Senshi-Admin). + Fixed an error in chain.c that was causing + segfaults with chains greater than 20 remailers. + Non-multipart MIME message errors fixed. + Fixed an error in rfc822.c (by Scott Renfro). + Fixed pgpget.c errors. (by Ulf Möller). + No longer permits automatic blocking of entire + domains or newsgroups. + Help files re-written (by Lucky Green). + Fixed inconsistencies between software name and + package name. + +2002-07-01 2.9b34 Encrypt-to directive is now supported. + Partial packets now properly expire if not + reassembled (by cmeclax). + Fixed an address blocking error introduced in + the last version (Peter Palfrader). + Various command line bug fixes. + +2002-07-10 2.9b35 Updated zlib due to security reasons. + Does not generate keys in client mode. + Uses binary format for id.log. + Assorted mpgp fixes (by Disastry). + Added support for storing the key passphrase + in the mix.cfg file. (by Disastry). + Now reports the contents of dest.alw for + middleman remailers (by Kat). + Reworked the OpenSSL version check in the + Install script. + +2002-08-09 2.9b36 Removed duplicate define of NYMDB from menu.h. + Fix a strncat() to undefined string variable in + mix.c (Closes: #584381). + Have the Makefile list all prerequisites for each + build target (Closes: #584386). + Change »majordomo@*« to »majordomo@« in default + dest.blk. The dest block engine does not under- + stand shell globs. Either substring matches or + regexen. + Fixed -T switch: if type2.list is not available fall + back to pubring.mix. + USE_IDEA is no longer default in config.h. It always + gets defined by the Install script instead. + Only create OpenPGP RSA keys if we compiled with + IDEA. + Make all filenames configurable in mix.cfg. + Add global mix.cfg support (compile time option). + The -G option now forces creation of new keys even in + client mode (Closes: #585176). + Random Documentation updates. + Default to not installing a .forward file in Install + script. + Fix unused variable warning on OpenBSD. + Fix public remailer keys getting re-signed + every time keys are requested (Closes: #478383). + Make smtp sending similar to local /usr/lib/sendmail + sending (wrt header/body separation; + Closes: #482052). + Add X-Loop header on mailbox forwarded messages. + Several small fixes by Sami Farin et al. + Detach correctly in daemon mode. + Minor Install script fixes. + +2002-08-20 2.9b37 OpenPGP enhancement release (fixes by Disastry). + Fix a small bug in pgpdata.c that stopped Mixmaster + from reading cipher preferences. + Fixed Passphrase reading in mpgp (the test program) + on Windows platform. + Add Hash: header when clearsigning. + Properly handle RSA keys whose key size is not a + multiple of 64. + Remove leading zeros from MPI. + Use MDC packets whenever possible. + List CAST5 and AES128 in cipher preferences. + Now displays Mixmaster version in the PGP version + header for non remailer/nym messages. + +2002-09-11 2.9b38 Install script deals with lack of patented IDEA + algorithm in a sane way (closes: #479020). + Compiled-in passphrase is now deprecated. + When expiring packet ids from id.log also expire + packets that are dated more than half a year in + the future. That way we get rid of invalid + packets introduced by the switch to a binary file. + The stats in remailer-stats replies always had a + peak at 00:00 GMT which was wrong. Fixed. + (closes: #597688). + Fixed a bug with reading armored keyrings consisting + of more than one armored block or having comments + in front of the one armored block. + In RSA PGP keys, we now set e=0x11. + Mixmaster now deletes error and temporary files + older than PACKETEXP time along with expired + partial packets. + Linux PPC fixes (and all other archs where char is + unsigned). + +2002-10-07 2.9b39 Added a new feature, --store-mail (-I), which will + deliver an encrypted mix packet to the message pool + without attempting being decrypted. + Made minor updates for WIN32 DLL. + When sending type II messages interactively you may + now choose a middleman remailer as the last hop + in your chain (closes: #481244). + If a footer.txt file exists its content will be + appended to outgoing messages leaving the remailer + network at this hop (closes: #490117). + List known remailers in remailer-conf reply (closes: + #480330). + The files created with "SENDMAIL outfile" have + different names now to scale beyond 10k files + (closes: #587593). + Fixed the "is a mailfolder" checking for -f. + Various fixes for Mixmaster when not using ncurses. + Added new option --config to allow loading of + configuration information from an alternate file. + POOL is now used correctly if set in mix.cfg. + ASCII armor checksum is now verified on PGP keys. + Corrected a bug where 1/4096 of pgp messages was + destroyed due an improper armor checksum + interpretation. + Added password-based authenticated SMTP for mix. + Currently, only AUTH LOGIN is supported. + Mixmaster now handles <CR><LF> in pubring.mix. + Removed incorrect NT service checks in mix.c. + Mixmaster now keeps no stats in client mode. + The pool is autmatically checked for waiting + messages in the client configuration. + Mixmaster now bears a DFSG-compliant license. + Fixed permissions on tarball release. + Documentation updates. + +2002-10-16 2.9b40 New option MAILIN that can be set to either a mbox + or Maildir folder. New mail will be read from it + and the folder cleared every time Mixmaster + processes its pool, or at MAILINTIME intervals + (closes: #597043). + The Mixmaster daemon now writes a pid file. + Mixmaster in daemon mode now catches SIGTERM and + SIGINT and finishes its current queue run and then + exits successfully. + Minor code formating cleanup and Install script + fixes. + +2002-12-15 2.9b41 The Mixmaster protocol version is now prepended + to the software version in the Mixmaster cap- + string. + Minor configuration default changes and Install + script fixes. + Install script now always uses "make" and not + "gmake". + IDEA detection is fixed on systems that provide + the header files but then turn out to not + have the required functions upon linking. + Install now properly identifies system-wide + installations of pcre and/or zlib if they + are installed in /usr/local/. + Mixmaster will now ensure that an address + submitted in a blocking request does not + match that of a known remailer before + adding it to the dest.blk file (patch + submitted by Trek. Vulnerability originally + discovered by noise and rabbi.) + Minor documentation fixes. + +2002-12-16 2.9b42 Minor documentation fixes. + Append another newline character to mbox folders + when storing a mail so that the mandatory empty + line is there. + +2002-12-16 2.9.0rc1 Release candidate. Packaging changes only. + +2002-12-25 2.9.0 Release version. Minor documentation changes + and version number change only. + +2003-11-08 2.9.1 Several changes for the Windows build. + Some Install script fixes. + Fixed a problem in blockrequest() where a buffer + could have been used after it was free()'d which + resulted in segfaults. + Check that feedback buffer is not null before + operating on it in chain_select(). + Closes #631353, thanks Sami Farin. + Make sure DH/DSA param file is actually opened + before writing to it. Fixes a segfault in + case it is not. + Handle a pool we cannot read correctly: don't close + the NULL dir handle (segfaults on *BSD). We also + print a warning in that case now. + Minor stats fix (gmtime vs localtime). + Fix pool stats bug. + +2004-03-20 3.0b1 FEATURE ENHANCEMENTS: + + The secret pgp keyring is now stored ASCII armored + with one key per ascii armor. + NB: Due to the bug with reading armored keyrings and + secring being stored armored now, it is not + advisable to downgrade Mixmaster unless special + action is taken to preserve the secret pgp + keyring. + Mixmaster now prompts for secret key passphrase when + started in daemon mode. + Mixmaster checks expiration and revocation status of + pgp keys, userids, and subkeys. + Mixmaster will not encrypt or sign with a revoked + or expired key. + When encrypting, Mixmaster uses preferences from + the primary userid (or the latest userid, if zero + or more than one primary userid is present.) + Mixmaster keys now have creation and expiration date. + It is not secured by any crypto voodoo, it's only + informational for clients to decide which keys to + use should they have more than one per remailer. + - on the client side we do not show remailers (and + therefore not use them) if their key is expired. + - the remailer refuses to decrypt messages to keys + that expired one month ago or earlier. + - the remailer automatically creates new Mixmaster + keys if the current ones are about to expire or + already are expired. + - the latest key from secring.mix is written to + key.txt. It used to be the first one. Since + creation of new mix key appends the key, this + seemed sensible. + Mixmaster now generates dummy messages automatically + as mail enters and exits the pool. + Applied Maildir feature patch by drt@un.bewaff.net, + with some changes by PP: + MAILBOX can now be a Maildir (closes: #586223). + New Star-Exclude feature by Colin Tuckley: + User-selected remailers can be excluded from + being chosen as random hops. + Have stats on intermediate vs. final hop count + (closes: #649900). + Add max capability for Type I. + Config option EXTFLAGS allows appending additional + flags to the capabilities string. (Hauke Lampe) + Config option PRECEDENCE allows setting the + Precedence: header on all outgoing mail. + (Hauke Lampe) + In order to serve help files in different languages + we need a way to reply to requests like + remailer-help-it. In order to not have to modify + the code for each and every new ressource, + Mixmaster now sends the file + requests/remailer-<something> to + remailer-<something> requests. + remailer-{help,key, stats,conf,adminkey} still are + special cases though. + Drop messages without timestamps and messages with + future timestamps. This abandons backwards + compatibility with Mixmaster 2.0.3 and earlier. + Mixmaster attempts to detect system clock + misconfigurations and refuses to run as a + remailer if there is a problem suspected. + Only applies to Mixmaster in remailer mode. + + BUG FIXES: + + Mixmaster in daemon mode reloads configuration on + SIGHUP. + In the curses interface chain selection it was not + possible to select a random last hop with a usenet + post message. Fixed (closes: #719165). + If remix was enabled and we had a Type-I Anon-Post-To + request we accidently randhoped it via the + configured default remailing chain (default: + *,*,*,*). + Fixed (closes: #729494). + In client mode (REMAIL n) the pool is flushed every + time mixmaster is run unless CLIENTAUTOFLUSH is + set to n. (closes: #676794: Rate implementation + doubled) + Found that weird bug that sometimes led to "Unknown + remailer version!" errors: In chain_randfinal() we + selected a random value between 0 and maxrem + instead of 0 and maxrem - 1. Mixmaster now uses + broken-chain info from stats. + Warn if remailer stats are older than a day or + from the future. + Don't send messages to ourselves via the mailsystem + but instead place them in the pool as incoming + messages so that they will get processed with the + next pool run. + No longer try to send a message if there are no + recipients left. + Set default max-randhops from 20 to 4. + Remix-To chain is limited by max-randhops limit as + well. + Messages to more than one remailer are dropped. + Nym support is not compiled in by default anymore. + The OpenPGP module mpgp now includes a man + page (large contributions by Trek). + Ignore 'No reliable remailers' problems when + randhopping messages in middleman mode. + That is better than dropping them. + Experimental feature: --redirect -l <chain>. + If you have a mixmaster message with a + chain starting with hop1 (you cannot know any + more because it already is encrypted) then + mix --redirect -l foo,bar < file + redirect the message so the chain is actually + foo,bar,hop1,... and places it in your pool. + If the total number of hops (which cannot be + known) exceeds 20 the message is damanged + and will fail at the 20th node. + +2004-05-06 3.0b2 + Use /dev/arandom instead of /dev/srandom on + OpenBSD (Nikolay Sturm). + Fall back to 3DES as Encrypt-Key cipher if we don't + have IDEA. - Laurent Fousse <laurent@komite.net> + Also sort mail into the various mboxes if autoreply + is not set. + Properly ignore whitespace in chain selection. + Removed unused functions in keymgt.c. + Added new options -V, --version, and --about. + Made manpage corrections. + Minor ncurses display tweaks. + General improvements for Win32 support (by + goblin and Peter Palfrader). + Preliminary Windows Installer work. + On Win32, default to Application Data/Mixmaster for + mixmaster's basedirectory. This can still be + overridden by MIXPATH or the registry entry + HKEY_CURRENT_USER\Software\Mixmaster\MixDir + Introduced new option "(e)dit configuration + file" in the main menu. + Changed 'q)uit' to 'q)uit w/o sending' in + menusend.c. + Added stats downloading support. Currently + works under Win32 only (by goblin). + Fixed bug in buffers.c. + +2006-06-24 3.0rc1 + Prefer pubring.asc over secring.pgp. + Support an unpublished dest.alw file. + Added MINLAT directive. Ensures randhopped + messages are sent through remailers of + latency of MINLAT time or greater + (suggested by Steve Crook). + Improved OpenSSL version checking in the + Install script. + Added full stats download support. + Fixed buffer overflow bug in keymgt.c. + +2008-03-03 3.0 + Changed name of WIN32 default config file + from mix.cfg.txt to mix.ini. + Changed pop3.cfg to pop3.ini on WIN32. + Updated Install script. + Minor documentation changes. + + + +Mixmaster maintainer history: + +1998-2000: Ulf Möller -- versions 2.9beta0 through 2.9beta22. +2000: Johannes Kroeger -- version 2.9beta23. +2001-2008: Len Sassaman -- versions 2.9beta24 through present. diff --git a/Install b/Install @@ -0,0 +1,1403 @@ +#!/bin/sh +# Mixmaster version 3.0 -- (C) 1999-2008 Anonymizer Inc. and others. + +# Mixmaster may be redistributed and modified under certain conditions. +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +# ANY KIND, either express or implied. See the file COPYRIGHT for +# details. + +# $Id: Install 979 2008-03-03 18:17:07Z rabbi $ + +#whereis program default-path +whereis() +{ + #echo "Looking for $1..." + found="" + for i in $* `which $1 2>&1` + do + if [ -f "$i" -a -x "$i" ] + then + found=$i + fi + done + if [ "$found" = "" ] + then + found=$2 +# echo "$1 not found. Using $found." +# else +# echo "$1 is at $found." + fi +} + +if echo -n | grep n >/dev/null +then + echo1="" + echo2="\c" +else + echo1="-n" + echo2="" +fi + +# readln text default +readln() +{ + echo $echo1 "$1 [$2] $echo2" + read ans + if [ -z "$ans" ] + then + ans="$2" + fi +} + +# findlib libxxx.a -- find and configure libraries +# Input: +# $1 library name +# $CONFIG library configure options +# $INCDIR possible include directories +# $SRCDIR possible library source directories +# $LIBDIR possible library binary directories +# +# Output: +# $found library directory +# $lib library name +# $INCDIR include directory if required, empty otherwise +# $LDFLAG linker options +# $LIB path to library file +# $MAKELIB Makefile entry to compile library +findlib() +{ + lib=$1 + libso=`echo $lib | sed 's/\.a$/.so/'` + echo "Looking for $lib..." + + found= + source= + type= + LIB= + LDFLAG= + MAKELIB= + + for i in /usr/local/lib /usr/lib /lib /usr/lib64 + do + if [ -r $i/$lib -o -r $i/$libso ] + then + found=$i + type=system + fi + done + + for i in $LIBDIR + do + if [ -r $i/$lib -o -r $i/$libso ] + then + found=$i + type=installed + fi + done + + for i in $SRCDIR + do + if [ -r $i/$lib -o -r $i/lib/$lib ] + then + found=$i + type=binary + fi + done + + if [ -r "$found/$libso" ] + then + echo "Found at $found/$libso." + elif [ -r "$found/$lib" ] + then + echo "Found at $found/$lib." + elif [ -r "$found/lib/$lib" ] + then + echo "Found at $found/lib/$lib." + fi + + for i in $SRCDIR + do + if [ -d $i -a ! "$type" = binary ] + then + source=$i + fi + done + + if [ "$source" != "" ] + then + echo "Found source directory $source." + if [ "$found" = "" ] + then + ans=y + else + echo "Use the source if the pre-installed library causes compilation problems." + readln "Use source?" n + fi + if [ "$ans" = "y" ] + then + found=$source + type=source + fi + fi + + if [ "$found" = "" ] + then + echo "Not found." + fi + + if [ -r $found/lib/$lib ] + then + LIB=$found/lib/$lib + else + LIB=$found/$lib + fi + if [ "$type" = system ] + then + LIB= + LDFLAG="-l`echo $lib | sed 's/^lib//;s/\.a$//'` -L$found" + if [ "$found" = "/usr/local/lib" ] + then + INCDIR="/usr/local/include $INCDIR" + fi + fi + + incdir=$INCDIR + INCDIR= + for i in $incdir + do + if [ -d $i ] + then + INCDIR=$i + fi + done + + if [ "$type" = source -o "$type" = binary ] + then + if [ ! -r $found/lib/$lib ] + then + MAKELIB="$found/$lib: + cd $found; make $lib" + fi + if [ -d $found/include ] + then + INCDIR=$found/include + else + INCDIR=$found + fi + fi + + if [ "$type" = source ] + then + dir=`pwd` + if [ "$dir" = "" ] + then + dir=$PWD + fi + + cd $found + if [ -x configure ] + then + echo "Configuring..." + ./configure $CONFIG + fi + if [ "$lib" = "libcrypto.a" ] + then + if [ -f config ] + then + sh config + elif [ -x Configure ] + then + ./Configure 2>tmp.$$ + cat tmp.$$ + readln "Your system?" `cat tmp.$$ | tr ' ' '\n' | grep -i \`uname\` | tail -1` + rm -f tmp.$$ + echo "Configuring..." + ./Configure $ans + fi + fi + cd $dir + fi +} + +# Global installation. + + +########################################################################## +umask 077 + +#FIXME -- Mixmaster now should be installed as root, and Install should +#create a remailer user. /var/spool/mixmaster is a good home. + +if [ `whoami` = root ] +then + echo "Please create a new user, e.g, \`mix', and install Mixmaster under that +user id. Installing Mixmaster as root is not recommended." + readln "Continue anyway?" n + if [ "$ans" = n ] + then + exit 1 + fi +fi + +MIXDIR="$PWD" +if [ "$MIXDIR" = "" ] +then + MIXDIR=`pwd` +fi +MIXCFG="$MIXDIR/conf" +MIXSRC="$MIXDIR/Src" +MIXDEST0=${MIXPATH:-$HOME/Mix} + +system=`uname` +if [ "$system" = "MS-DOS" ] +then + system=msdos +fi + +if [ "$HOSTNAME" = "" ] +then + HOSTNAME=`hostname` +fi +if [ "$HOSTNAME" = "" ] +then + HOSTNAME=msdos + system=msdos +fi + +if [ "$system" = msdos ] +then + MIXDEST0=${MIXPATH:-C:/Mix} +fi + +if [ -f "$MIXSRC/Makefile" ] +then + if grep "#Makefile generated.*$HOSTNAME" $MIXSRC/Makefile + then + echo "Found a Makefile for this system." + readln "Use this Makefile?" y + if [ "$ans" = n ] + then + rm -f "$MIXSRC/Makefile" + fi + else + readln "Remove old Makefile?" y + if [ "$ans" = y ] + then + rm -f "$MIXSRC/Makefile" + fi + fi +fi + +if [ -f "$MIXSRC/Makefile" ] +then + MIXDEST=`grep "DSPOOL=" $MIXSRC/Makefile | sed 's/.*DSPOOL=..//;s/\".*//'` + if [ "$MIXDEST" = "" ] + then + MIXDEST="$MIXDEST0" + fi +fi + +if [ "$MIXDEST" = "" ] +then + readln "Mixmaster directory?" "$MIXDEST0" + MIXDEST=$ans +else + echo "Mixmaster directory: $MIXDEST" +fi + +if [ ! -d "$MIXDEST" ] +then + echo "Creating directory $MIXDEST" + mkdir "$MIXDEST" +fi + +if [ ! -d "$MIXDEST" ] +then + echo "Cannot not create $MIXDEST" + exit 1 +fi + +if [ -f "$MIXDEST/mix.cfg" ] +then + if [ -f "$MIXDEST/secring.mix" ] + then + remailer=y + if grep PASSPHRASE "$MIXDEST/mix.cfg" >/dev/null + then + PASSINCONFIG=1 + fi + else + readln "Do you want to set up a remailer?" n + remailer=$ans + fi +elif [ -f "$MIXDEST/mixmaster.conf" ] +then + echo "Upgrading from Mixmaster 2.0.*" + remailer=n +else + readln "Do you want to set up a remailer?" y + remailer=$ans +fi + + +ans="" +if [ "$remailer" = "y" ] +then + ans="n" + if [ "$PASSINCONFIG" != 1 ] + then + echo "" + echo "You can either compile your secret passphrase into the binary +or you can set it in your config file. Note that the former does not +really increase security as the passphrase can still be discovered by +running something like \`strings mixmaster'." + echo "" + echo "Most users should answer \`n' to this question:" + echo "" + readln "Do you want to compile the passphrase into the binary?" n + fi + + rm -f "$MIXSRC/mix.o" # make sure our new passphrase takes effect + if [ "$ans" = "y" ] + then + ans="" + echo "Please enter a passphrase for your remailer (must be the same +whenever you re-compile Mixmaster)." + read ans + + if [ "$ans" != "" ] + then + PASS="PASS=$ans" + else + echo "WARNING: not setting a passphrase" + fi + else + if [ "$PASSINCONFIG" != 1 ] + then + ans="" + echo "Please enter a passphrase for your remailer (it will be +stored in mix.cfg in clear)." + read ans + + if [ "$ans" = "" ] + then + echo "WARNING: setting empty passphrase" + fi + PASSPHRASE="PASSPHRASE $ans" + if [ -f $MIXDEST/mix.cfg ] + then + echo "$PASSPHRASE" >> $MIXDEST/mix.cfg + fi + fi + fi +fi + + +cd "$MIXSRC" +if [ ! -f Makefile ] +then + LIBS= + INC= + DEF= + LDFLAGS= + + if [ ! -z "$PASS" ] + then + DEF="$DEF -DCOMPILEDPASS='\"\$(PASS)\"'" + fi + + if [ "$system" = msdos ] + then + readln "Use WIN32 GUI?" y + if [ "$ans" = y ] + then + system=win32 + LDFLAGS=-lwsock32 + fi + fi + if [ "$system" = SunOS ] + then + LDFLAGS="-lsocket -lnsl" + fi + + LIBDIR= + INCDIR= + SRCDIR=zlib* + findlib libz.a + if [ "$found" = "" ] + then + readln "Continue anyway?" n + if [ "$ans" = "n" ] + then + echo "Please install zlib 1.1.4 or 1.2.3 or greater now." + exit 1 + fi + else + ZLIB="$MAKELIB" + DEF="$DEF -DUSE_ZLIB" + LIBS="$LIBS $LIB" + LDFLAGS="$LDFLAGS $LDFLAG" + if [ "$INCDIR" != "" ] + then + INC="$INC -I$INCDIR" + fi + fi + + LIBDIR= + INCDIR="/usr/include /usr/include/pcre /usr/local/pcre/include" + SRCDIR=pcre* + findlib libpcre.a + if [ "$found" != "" ] + then + PCRE="$MAKELIB" + DEF="$DEF -DUSE_PCRE" + LIBS="$LIBS $LIB" + LDFLAGS="$LDFLAGS $LDFLAG" + if [ "$INCDIR" != "" ] + then + INC="$INC -I$INCDIR" + fi + fi + + opensslinfo="Please get OpenSSL 0.9.6l or greater from http://www.openssl.org/" + opensslwarning6="WARNING: This version of OpenSSL contains known vulnerabilities. Please upgrade to OpenSSL 0.9.6l or greater!" + opensslwarning7="WARNING: This version of OpenSSL contains known vulnerabilities. Please upgrade to OpenSSL 0.9.7c or greater!" + opensslwarning0=$opensslwarning7 + LIBDIR=/usr/local/ssl/lib + INCDIR="/usr/include /usr/include/ssl /usr/lib/ssl/include /usr/local/ssl/include" + SRCDIR="openssl*" + + opensslwarn() + { + if [ "$1" = "6" ] + then + echo $opensslwarning6 + elif [ "$1" = "7" ] + then + echo $opensslwarning7 + else + echo $opensslwarning0 + fi + readln "Continue anyway?" y + if [ "$ans" = "n" ] + then + echo $opensslinfo + exit 1 + fi + } + + if [ "$system" = win32 ] + then + findlib libeay32.a + else + findlib libcrypto.a + fi + if [ "$found" = "" ] + then + echo $opensslinfo + exit 1 + fi + + OPENSSLLIB="$LIB" + LIBS="$LIBS $LIB" + LDFLAGS="$LDFLAGS $LDFLAG" + if [ "$MAKELIB" != "" ] + then + OPENSSL="$found/$lib: + cd $found/crypto; make" + fi + if [ -d "$INCDIR/openssl" ] + then + INC="$INC -I$INCDIR" + else + # detect old SSLeay versions + if [ -f "$INCDIR/crypto.h" ] + then + version=800 + if grep OPENSSL "$INCDIR/crypto.h" > /dev/null + then + version=920 + fi + fi + fi + + # Find the OpenSSL version header + if [ -f "$INCDIR/openssl/opensslv.h" ] + then + version=`grep 'SSL.*_VERSION_NUMBER.*0x' $INCDIR/openssl/opensslv.h | sed 's/.*0x0*//;s/[ ].*//;s/L$//' | tr '[a-f]' '[A-F]'` + elif [ -f "$INCDIR/opensslv.h" ] + then + version=`grep 'SSL.*_VERSION_NUMBER.*0x' $INCDIR/opensslv.h | sed 's/.*0x0*//;s/[ ].*//;s/L$//' | tr '[a-f]' '[A-F]'` + fi + if [ "$version" = "" ] + then + echo "Warning: Can't find OpenSSL version number!" + readln "Continue anyway?" y + if [ "$ans" = "n" ] + then + echo $opensslinfo + exit 1 + fi +# +# Here we match against known OpenSSL versions +# + elif [ "$version" = "90581F" ] + then + decimalversion=9459743 + echo "Compiling with OpenSSL 0.9.5a." + opensslwarn 6 + elif [ "$version" = "90601F" ] + then + decimalversion=9461791 + echo "Compiling with OpenSSL 0.9.6a." + opensslwarn 6 + elif [ "$version" = "90602F" ] + then + decimalversion=9461807 + echo "Compiling with OpenSSL 0.9.6b." + opensslwarn 6 + elif [ "$version" = "90603F" ] + then + decimalversion=9461823 + echo "Compiling with OpenSSL 0.9.6c." + opensslwarn 6 + elif [ "$version" = "90604F" ] + then + decimalversion=9461839 + echo "Compiling with OpenSSL 0.9.6d." + opensslwarn 6 + elif [ "$version" = "90605F" ] + then + decimalversion=9461855 + echo "Compiling with OpenSSL 0.9.6e." + opensslwarn 6 + elif [ "$version" = "90606F" ] + then + decimalversion=9461871 + echo "Compiling with OpenSSL 0.9.6f." + opensslwarn 6 + elif [ "$version" = "90607F" ] + then + decimalversion=9461887 + echo "Compiling with OpenSSL 0.9.6g." + opensslwarn 6 + elif [ "$version" = "90608F" ] + then + decimalversion=9461903 + echo "Compiling with OpenSSL 0.9.6h." + opensslwarn 6 +elif [ "$version" = "90609F" ] + then + decimalversion=9461919 + echo "Compiling with OpenSSL 0.9.6i." + opensslwarn 6 + elif [ "$version" = "9060A0" ] + then + decimalversion=9461920 + echo "Compiling with OpenSSL 0.9.6j." + opensslwarn 6 + elif [ "$version" = "9060B0" ] + then + decimalversion=9461936 + echo "Compiling with OpenSSL 0.9.6k." + opensslwarn 6 + elif [ "$version" = "9060C0" ] + then + decimalversion=9461952 + echo "Compiling with OpenSSL 0.9.6l." + elif [ "$version" = "9060D0" ] + then + decimalversion=9461968 + echo "Compiling with OpenSSL 0.9.6m." + elif [ "$version" = "90700F" ] + then + decimalversion=9465871 + echo "Compiling with OpenSSL 0.9.7." + opensslwarn 7 + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90701F" ] + then + decimalversion=9465887 + echo "Compiling with OpenSSL 0.9.7a." + opensslwarn 7 + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90702F" ] + then + decimalversion=9465903 + echo "Compiling with OpenSSL 0.9.7b." + opensslwarn 7 + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90703F" ] + then + decimalversion=9465919 + echo "Compiling with OpenSSL 0.9.7c." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90704F" ] + then + decimalversion=9465935 + echo "Compiling with OpenSSL 0.9.7d." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90705F" ] + then + decimalversion=9465951 + echo "Compiling with OpenSSL 0.9.7e." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90706F" ] + then + decimalversion=9465967 + echo "Compiling with OpenSSL 0.9.7f." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90707F" ] + then + decimalversion=9465983 + echo "Compiling with OpenSSL 0.9.7g." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90708F" ] + then + decimalversion=9465999 + echo "Compiling with OpenSSL 0.9.7h." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90709F" ] + then + decimalversion=9466015 + echo "Compiling with OpenSSL 0.9.7i." + DEF="$DEF -DUSE_AES" + + elif [ "$version" = "9070AF" ] + then + decimalversion=9466031 + echo "Compiling with OpenSSL 0.9.7j." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "9070BF" ] + then + decimalversion=9466047 + echo "Compiling with OpenSSL 0.9.7k." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "9070CF" ] + then + decimalversion=9466063 + echo "Compiling with OpenSSL 0.9.7l." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "9070DF" ] + then + decimalversion=9466079 + echo "Compiling with OpenSSL 0.9.7m." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "9070EF" ] + then + decimalversion=9466095 + echo "Compiling with OpenSSL 0.9.7n." + echo "This version was unreleased at the time of packaging." + echo "It is not guaranteed to work. Please report any problems." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90800F" ] + then + decimalversion=9469967 + echo "Compiling with OpenSSL 0.9.8." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90801F" ] + then + decimalversion=9469983 + echo "Compiling with OpenSSL 0.9.8a." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90802F" ] + then + decimalversion=9469999 + echo "Compiling with OpenSSL 0.9.8b." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90803F" ] + then + decimalversion=9470015 + echo "Compiling with OpenSSL 0.9.8c." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90804F" ] + then + decimalversion=9470031 + echo "Compiling with OpenSSL 0.9.8d." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90805F" ] + then + decimalversion=9470047 + echo "Compiling with OpenSSL 0.9.8e." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90806F" ] + then + decimalversion=9470063 + echo "Compiling with OpenSSL 0.9.8f." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90807F" ] + then + decimalversion=9470079 + echo "Compiling with OpenSSL 0.9.8g." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90808F" ] + then + decimalversion=9470095 + echo "Compiling with OpenSSL 0.9.8h." + DEF="$DEF -DUSE_AES" + elif [ "$version" = "90809F" ] + then + decimalversion=9470111 + echo "Compiling with OpenSSL 0.9.8h." + echo "This version was unreleased at the time of packaging." + echo "It is not guaranteed to work. Please report any problems." + DEF="$DEF -DUSE_AES" + fi +# +# Now we try to guess about unknown versions: +# + if [ "$decimalversion" = "" ] + then + decimalversion=`echo 16i $version p | dc` + fi + if [ "$decimalversion" = "" ] + then + echo "Warning: This version: ${version} of OpenSSL is not recognized." + readln "Continue anyway?" y + if [ "$ans" = "n" ] + then + echo $opensslinfo + exit 1 + else + echo "Does this version of OpenSSL contain AES support?" + readln "If unsure of the answer, say \`n'" n + if [ "$ans" = "y" ] + then + DEF="$DEF -DUSE_AES" + fi + fi + elif [ "$decimalversion" -lt "2336" ] # 920 + then + echo "This version: ${version} of SSLeay is not supported." + echo $opensslinfo + exit 1 + elif [ "$decimalversion" -lt "9449728" ] # 903100 + then + echo "This version: ${version} of OpenSSL is not supported." + echo $opensslinfo + exit 1 + elif [ "$decimalversion" -gt "9470111" ] # 0.9.8h + then + echo "Warning: This version: ${version} of OpenSSL is untested." + readln "Continue anyway?" y + if [ "$ans" = "n" ] + then + echo $opensslinfo + exit 1 + else + echo "Does this version of OpenSSL contain AES support?" + readln "If unsure of the answer, say \`n'" n + if [ "$ans" = "y" ] + then + DEF="$DEF -DUSE_AES" + fi + fi + fi + + LIBDIR= + INCDIR=/usr/include/ncurses + SRCDIR=ncurses* + CONFIG=--enable-termcap + if [ "$TERMINFO" != "" ] + then + CONFIG="--datadir=$TERMINFO" + fi + if [ -d /usr/share/terminfo ] + then + CONFIG= + fi + if [ -d /usr/lib/terminfo ] + then + CONFIG=--datadir=/usr/lib/terminfo + fi + + if [ `uname` = OpenBSD ] + then + findlib libcurses.a + else + findlib libncurses.a + fi + if [ "$found" = "" ] + then + if [ "$system" != win32 ] + then + readln "Do you want to use Mixmaster's menu-based user interface?" y + if [ "$ans" = "y" ] + then + echo "Please install ncurses now. It is available from http://www.clark.net/pub/dickey/ncurses/ncurses.tar.gz" + exit 1 + fi + fi + else + DEF="$DEF -DUSE_NCURSES" + if [ "$type" = system -o "$type" = installed ] + then + LIBS="$LIBS $LIB" + LDFLAGS="$LDFLAGS $LDFLAG" + else + LIBS="$LIBS $found/lib/$lib" + NCURSES="$found/lib/$lib: + cd $found/ncurses; make ../lib/$lib" + fi + if [ "$INCDIR" != "" ] + then + INC="$INC -I$INCDIR" + elif [ -f "/usr/include/ncurses.h" ] + then + DEF="$DEF -DHAVE_NCURSES_H" + fi + fi + + ideawarn() + { + echo " + WARNING: Your version of OpenSSL has been configured without IDEA support. + If you continue, Mixmaster will be installed with reduced functionality. + This means (among other things) that Mixmaster will not create an RSA + OpenPGP key (to avoid mail loss in the Type I system). You may want to + re-install OpenSSL before proceeding. + + This will not concern you if you only plan to run a type II remailer or + simply want a type II client." + readln "Continue anyway?" y + if [ "$ans" = "n" ] + then + exit 1 + fi + } + + if [ "$system" = OpenBSD ] + then + LIBDIR= + INCDIR= + SRCDIR=idea* + findlib libidea.a + if [ "$found" = "" ] + then + ideawarn + else + DEF="$DEF -DUSE_IDEA" + IDEALIB="$MAKELIB" + LIBS="$LIBS $LIB" + LDFLAGS="$LDFLAGS $LDFLAG" + if [ "$INCDIR" != "" ] + then + INC="$INC -I$INCDIR" + fi + fi + elif [ "$system" = msdos -o "$system" = win32 ] + then + DEF="$DEF -DUSE_IDEA" + else + echo "Checking for IDEA support..." + cat <<END >tmptst.c +#include <openssl/idea.h> +int main() { + void *dummy; + dummy = idea_cfb64_encrypt; + exit(0); +} +END + if gcc $LDFLAGS $INC tmptst.c -o tmptst $OPENSSLLIB + then + DEF="$DEF -DUSE_IDEA" + else + ideawarn + fi + rm -f tmptst.c tmptst + fi + + echo "testing for setenv()..." + cat <<END >tmptst.c +int main() { +#include <stdlib.h> + setenv("TZ", "GMT", 0); + exit(0); +} +END + if gcc tmptst.c -o tmptst + then + DEF="$DEF -DHAVE_SETENV" + fi + echo "done" + rm -f tmptst.c tmptst + +# if [ "$MIXDEST" = "$HOME/Mix" ] +# then +# SPOOL= +# else + SPOOL=-DSPOOL=\'\"$MIXDEST\"\' +# fi + + echo "Generating Makefile." + echo "#Makefile generated on $HOSTNAME `date`" >Makefile + sed -e "s#%MIXDIR#$SPOOL#" \ + -e "s#%LIBS#$LIBS#" \ + -e "s#%LDFLAGS#$LDFLAGS#" \ + -e "s#%INC#$INC#" \ + -e "s#%DEF#$DEF#" < Makefile.in >> Makefile +# echo "$ZLIB" >>Makefile +# echo "$PCRE" >>Makefile + echo "$IDEALIB" >>Makefile + echo "$NCURSES" >>Makefile + echo "$OPENSSL" >>Makefile +fi + + + + + +echo "Compiling. Please wait." +whereis make +make=$found + +if [ "$system" = win32 ] +then +# (cd zlib*; make libz.a) +# (cd pcre*; make libpcre.a) + if [ "$PASS" != "" ] + then + $make "$PASS" dllmix + else + $make dllmix + fi +else + if [ "$PASS" != "" ] + then + $make "$PASS" + else + $make + fi +fi + +if [ -x mixmaster ] +then + echo +else + echo "Error: The compilation failed. Please consult the documentation (section +\`Installation problems')." + readln "Remove the old Makefile?" y + if [ "$ans" = y ] + then + rm -f Makefile + fi + exit 1 +fi + +if [ -f "$MIXDEST/mixmaster.conf" -a ! -f "$MIXDEST/mix.cfg" ] +then + export MIXDEST + export MIXDIR + export MIXSRC + "${MIXDIR}/upgrade" + exit 0 +fi + +if [ -f mixmaster.exe ] +then + cp mixmaster.exe "$MIXDEST" +else + cp mixmaster "$MIXDEST" +fi + +cd "$MIXCFG" +for i in mlist.txt pubring.mix rlist.txt pubring.asc +do + if [ ! -f "$MIXDEST/$i" ] + then + cp "$i" "$MIXDEST" + fi +done + +if [ "$remailer" = "y" ] +then + cd "$MIXCFG" + for i in adminkey.txt dest.alw + do + if [ ! -f "$MIXDEST/$i" ] + then + cp "$i" "$MIXDEST" + fi + done +fi + +if [ "$remailer" = "n" ] +then + if [ ! -f "$MIXDEST/mix.cfg" ] + then + whereis sendmail /usr/lib/sendmail /usr/sbin/sendmail + echo "SENDMAIL $found -t" >"$MIXDEST/mix.cfg" + cat mix.cfg >>"$MIXDEST/mix.cfg" + fi + echo "Client installation complete." + exit +fi + +for i in *.blk +do + if [ ! -f "$MIXDEST/$i" ] + then + cp "$i" "$MIXDEST" + fi +done + +cd "$MIXDEST" + +installed=n +if [ -f mix.cfg ] +then + if grep REMAILERADDR mix.cfg >/dev/null + then + installed=y + fi +fi + +if [ "$installed" = "n" ] +then + Date=`date` + whereis sendmail /usr/lib/sendmail /usr/sbin/sendmail + sendmail=$found + + echo "Mixmaster can be installed in the low-maintenance \`middleman' mode. +In that mode, it will send mail to other remailers only, to avoid +complaints about anonymous messages." + readln "Install as middleman?" n + middle=$ans + + readln "The e-mail address of your remailer:" `whoami`@$HOSTNAME + RMA=$ans + + echo "Do you want Mixmaster to send auto-replies to messages it does not +understand (If the address <$RMA> is also used" + readln "for mail to be read by a human, type \`n')?" y + autoreply=$ans + + if [ "$middle" = n ] + then + readln "An address to appear in the \`From:' line of anonymous messages:" `echo $RMA | sed 's/.*@/nobody@/'` + RAA=$ans + + readln "Address for complaints to be sent to:" `echo $RMA | sed 's/.*@/abuse@/'` + CA=$ans + else + RAA=$RMA + CA=$RMA + fi + + echo "Choose a name for your remailer. It will appear in remailer status messages." + readln "Long name:" "Anonymous Remailer" + RMN=$ans + + if [ "$middle" = n ] + then + echo "Choose a name to be used in the \`From:' line of remailed messages." + readln "Anon long name:" "Anonymous" + RAN=$ans + fi + + readln "A short name to appear in lists:" `echo $HOSTNAME|sed 's/\..*//'` + SN=$ans + + readln "Accept Mixmaster (Type II) messages?" y + mix=$ans + + readln "Accept PGP (Type I) remailer messages?" n + pgp=$ans + + unencrypted=n + if [ "$pgp" = "y" ] + then + readln "Accept unencrypted remailer messages?" n + unencrypted=$ans + fi + + echo "Mixmaster will log error messages and warnings. Do you want to log" + readln "informational messages about normal operation as well?" y + if [ "$ans" = y ] + then + verbose=2 + else + verbose=1 + fi + + readln "Filter binary attachments?" n + binfilter=$ans + + if [ "$middle" = n ] + then + if [ "$autoreply" = y ] + then + readln "Allow users to add themselves to the list of blocked addresses?" y + autoblock=$ans + fi + + echo "Do you want to allow posting? Newsgroups can be restricted in dest.blk. +y)es, post locally; use m)ail-to-news gateway; n)o." + readln "Allow posting to Usenet?" m + post="$ans" + if [ "$ans" = y ] + then + whereis inews /usr/lib/news/inews + readln "News posting software:" "$found -h" + news=$ans + readln "Organization line for anonymous Usenet posts:" "Anonymous Posting Service" + orga=$ans + readln "Use anti-spam message IDs?" y + mid=$ans + elif [ "$ans" = m ] + then + readln "Mail-to-news gateway:" mail2news@nym.alias.net + news=$ans + fi + fi + +# Commented the poolsize question out, since poolsize is the least +# important of the three pool parameters. +# +# echo "How many messages do you want to keep in the reordering pool? +#A larger pool is more secure, but also causes higher latency. +#0 means to remail immediately." +# readln "Pool size:" 45 +# poolsize=$ans + + mbox= + if [ -f ~/.forward ] + then + mbox=`head -1 ~/.forward | sed 's/^"//;s/"$//'` + if echo "$mbox" | grep 'mix' >/dev/null 2>/dev/null + then + mbox= + elif echo "$mbox" | grep 'procmail' >/dev/null 2>/dev/null + then + if grep mix ~/.procmailrc >/dev/null 2>/dev/null + then + mbox= + fi + fi + fi + + if [ "$mbox" = "" ] + then + mbox=${MAIL:-/usr/spool/mail/$NAME} + touch "$mbox" + if [ ! -w "$mbox" ] + then + echo "$mbox is not writeable." + readln "Mailbox for non-remailer messages:" "${MIXDEST}/mbox" + mbox=$ans + fi + fi + + cat <<END >mix.cfg +# mix.cfg -- installed $Date +SENDMAIL $sendmail -t + +# Where to store non-remailer messages: +MAILBOX $mbox +#MAILABUSE mbox.abuse +#MAILBLOCK mbox.block +#MAILUSAGE mbox.usage +#MAILANON mbox.anon +#MAILERROR mbox.error +#MAILBOUNCE mbox.bounce + +REMAIL y +MIDDLEMAN $middle + +BINFILTER $binfilter +AUTOBLOCK $autoblock + +ERRLOG error.log +VERBOSE $verbose + +# Remailer name and addresses +REMAILERADDR $RMA +ANONADDR $RAA +COMPLAINTS $CA + +SHORTNAME $SN +REMAILERNAME $RMN +ANONNAME $RAN + +# Supported formats: +MIX $mix +PGP $pgp +UNENCRYPTED $unencrypted + +# Maximum message size in kB (0 for no limit): +SIZELIMIT 0 + +# Usenet news: +NEWS $news +ORGANIZATION $orga +MID $mid + +# Remailing strategy: +SENDPOOLTIME 15m +POOLSIZE 45 +RATE 65 +INDUMMYP 10 +OUTDUMMYP 90 +CHAIN *,*,*,* +IDEXP 7d +PACKETEXP 7d + +$PASSPHRASE + +END + +fi # not yet installed + + +REPLACE="s/%RMN/$RMN/g;s/%RMA/$RMA/g;s/%CA/$CA/g;s/%RAA/$RAA/g" +if [ "$installed" = "n" ] +then + cd "$MIXCFG" + if [ ! -f "$MIXDEST/help.txt" ] + then + sed "$REPLACE" < intro.hlp >"$MIXDEST/help.txt" + if [ "$mix" = y ] + then + sed "$REPLACE" < mix.hlp >>"$MIXDEST/help.txt" + fi + if [ "$unencrypted" = y ] + then + sed "$REPLACE" < type1.hlp >>"$MIXDEST/help.txt" + if [ "$pgp" = y ] + then + sed "$REPLACE" < pgp.hlp >>"$MIXDEST/help.txt" + fi + elif [ "$pgp" = y ] + then + sed "$REPLACE" < pgponly.hlp >>"$MIXDEST/help.txt" + fi + if [ "$post" = y ] + then + if [ "$pgp" = y -o "$unencrypted" = y ] + then + sed "$REPLACE" < news.hlp >>"$MIXDEST/help.txt" + fi + fi + sed "$REPLACE" < end.hlp >>"$MIXDEST/help.txt" + fi + + for i in *.txt.in + do + j=`echo $i | sed 's/\.in$//'` + if [ ! -f "$MIXDEST/$j" ] + then + sed "$REPLACE" < "$i" >"$MIXDEST/$j" + fi + done + cd "$MIXDEST" +fi + +echo +if [ ! -f secring.mix ] +then + echo "Generating secret keys. This may take a while..." +else + echo "Updating secret keys..." +fi +./mixmaster -K +if [ -f key.txt ] +then + echo "Done." + echo +else + echo "Installation failed. Please consult the Mixmaster documentation." + exit 1 +fi + +if [ "$system" = msdos -o "$system" = win32 ] +then + exit +fi + +umask 033 + +# Set .forward? +# +set=y +# FIXME -- Mixmastger should run in daemon mode, not from procmail +# Make the Install script do that. + +if grep procmail ~/.forward >/dev/null 2>/dev/null +then + if grep mix ~/.procmailrc >/dev/null 2>/dev/null + then + echo "Mixmaster is installed in your .procmailrc file." + set=n + fi +fi + +if [ "$set" = y -a -f ~/.forward ] +then + echo "Your current .forward is:" + cat ~/.forward + echo + if grep mix ~/.forward >/dev/null 2>/dev/null + then + echo "Mixmaster already is installed in your .forward file." + set=n + elif [ "$mbox" != "" ] + then + if echo "$mbox" | grep '|' >/dev/null 2>/dev/null + then + echo "Mixmaster will pipe messages to $mbox" + elif echo $mbox | grep '@' >/dev/null 2>/dev/null + then + echo "Mixmaster will forward messages to $mbox" + else + echo "Mixmaster will store messages to $mbox" + fi + fi +fi + +if [ "$set" = y ] +then + echo "Set .forward to the following line:" + echo "\"|${MIXDEST}/mixmaster -RM\"" + if [ -f ~/.forward ] + then + readln "Overwrite now?" n + else + readln "Do that now?" n + fi + if [ "$ans" = "y" ] + then + echo "\"|${MIXDEST}/mixmaster -RM\"" >~/.forward + fi +fi + +#FIXME -- we need a second script that can re-generate help files +# when the conf changes. + +if [ "$RMA" != "" ] +then + echo " +Mixmaster will send the following files as auto-replies: +Mail to <$RMA> with Subject: remailer-help => help.txt" + echo "Mail to <$RMA> with Subject: remailer-adminkey => adminkey.txt +Remember to add your Remailer Admin public PGP key to the adminkey.txt file." + if [ "$autoblock" = y ] + then + echo "Mail to <$RMA> with line DESTINATION-BLOCK => blocked.txt" + fi + if [ "$autoreply" = y ] + then + echo "Other mail to <$RMA> => usage.txt" + echo + if [ "$CA" != "$RMA" ] + then + echo "If you arrange for mail to <$CA> and <$RAA> +to be forwarded to <$RMA>: +Mail to <$CA> => abuse.txt +Mail to <$RAA> => reply.txt" + fi + fi +fi + +echo +echo "Mixmaster installation complete." + diff --git a/README b/README @@ -0,0 +1,191 @@ +Mixmaster 3.0 -- anonymous remailer software -- (C) 1999 - 2000 Anonymizer Inc. + (C) 2000-2008 The Mixmaster Development Team +------------------------------------------------------------------------------- + +This program consists of + +* a remailer client: + + The remailer client supports sending anonymous mail using Cypherpunk and + Mixmaster remailers. It supports OpenPGP encryption (compatible with PGP 2, + PGP 5 and up, and GnuPG). + + The client can be used with a menu-based user interface and with command line + options. + +* a remailer: + + The remailer supports the Cypherpunk and Mixmaster message formats. It can + be integrated with the mail delivery system of Unix-based computers or use + the POP3 and SMTP protocols for mail transfer. Mixmaster includes an + automated abuse-handling system. + +Please report any problems via the bug and patch trackers at +http://sourceforge.net/projects/mixmaster/ + + +Installation: +------------ + +Libraries: + + Mixmaster requires the libraries OpenSSL, zlib, and pcre. + + If you want to use the menu-based user interface, you also need the ncurses + library. If these libraries are not installed on your system, you will need + to obtain the latest versions from the sources below and extract them in the + the Src/ directory first. + + OpenSSL is available from http://www.openssl.org/source/ + + Ncurses can be obtained from http://ftp.gnu.org/pub/gnu/ncurses/ + + The Perl Compatable Regular Expressions library can be obtained from + ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ + + The zlib compression libraries can be obtained from + http://www.gzip.org/zlib/ + +To install or upgrade Mixmaster, type `./Install'. + +Mixmaster clients rely on pingers to compile statistics and keyrings for +currently operating remailers. A list of public pingers can be obtained from +http://www.noreply.org/allpingers/. + +Alternatively clients can operate their own pingers to generate statistics. +Pinger software can be obtained from http://www.palfrader.org/echolot/. If you +choose this option, please publish the pinger results for the benefit of other +Mixmaster users and notify the metastats maintainer at admin@mixmin.net. + +The required files published by pingers are:- + pubring.asc Type 1 remailer keys + pubring.mix Type 2 remailer keys + rlist.txt List of reliable type 1 remailers + mlist.txt List of reliable type 2 remailers + type2.list List of known type 2 remailers (optional) + +Using the remailer client: +------------------------- + +To use the menu-based user interface, simply run `mixmaster'. To send an +anonymous or pseudonymous reply to a message from within your mail or news +reader, you can pipe it to `mixmaster'. + +The interactive mode supports sending mail and contains a simple mail reading +function. OpenPGP messages are encrypted and decrypted automatically. + +In the non-interactive mode, Mixmaster reads a message from a file or from its +standard input. The command line options are described in the manual page +(mixmaster.1). + + +Mixmaster as a remailer: +----------------------- + +The Mixmaster remailer can be installed on any account that can receive mail. +Non-remailer messages will be delivered as usual. If you have root access, you +may want to create a new user (e.g., `remailer') and install Mixmaster under +that user id. + +The Install script provides a simple way to set up the remailer. More +information about configuring Mixmaster can be found in the manual page. +Typically, incoming mail is piped to "mixmaster -RM". In a UUCP setting, it may +be useful to use just "mixmaster -R", and run "mixmaster -S" once all messages +have arrived. + +Announcing a new remailer to the public is most commonly done by posting the +remailer keys and capabilities to alt.privacy.anon-server as well as the +"remops" mailing list. Information about the remops list can be found here: +http://lists.mixmin.net/mailman/listinfo/remops + + +Installation problems: +--------------------- + +In case one of the libraries Mixmaster uses is installed incorrectly on your +system, place the library source code (available from the locations listed +above) in the Src directory, remove the old Makefile, run the Install script +again and answer `y' when asked whether to use the source code. + +The ncurses library can use termcap and terminfo databases. The Mixmaster +Install script tries to find out whether terminfo is available. If you get a +"Can't open display" error when starting the Mixmaster menu, run "./configure +--enable-termcap; make lib/libncurses.a" in the ncurses directory. + + +Security notes: +-------------- + +The ciphers and the anonymizing mix-net protocol used in Mixmaster correspond +to the state of the art (see the Security Considerations section of the +Mixmaster Protocol specification for details). However, no security proofs +exist for any practical cryptosystem. It is unlikely that their security will +be broken, but there is no "perfect security". Software can also contain +implementation errors. The complete Mixmaster source code is available for +public review, so that everyone can verify what the program does, and it is +unlikely that security related errors or secret back doors in the software +would go unnoticed. + +No software is secure if run in an insecure environment. For that reason you +must make sure that there is no malicious software (such as viruses) running on +your computer. Deleted files and even passphrases can in many cases be read +from the hard disk if an adversary has access to the computer. The use of disk +encryption programs is recommended to avoid this risk. + +Anonymous messages are secure as long as at least one of the remailers you use +in a chain is honest. You can use up to 20 remailers in a chain, but +reliability and speed decrease with longer chains. Four is a reasonable number +of remailers to use. Many remailer operators sign their keys. You should verify +those signatures with OpenPGP to make sure that you have the actual remailer +keys. + +Anonymous keys usually cannot be introduced to the OpenPGP web of trust without +giving up anonymity. For that reason, this client will use any OpenPGP key +found on the key ring, whether it is certified or not. Your key ring must not +contain any invalid keys when used with this program. + +If you want to use a pseudonym, the client will ask you for a passphrase to +protect the nym database. Your passphrase should be long, and hard to guess. +Anyone who gets hold of your nym database and private keys and can determine +the passphrase will be able to compromise your pseudonymous identities. Note +that some operating systems may store your passphrase on your hard disk in +clear. + +While a good client passphrase can protect your keys if someone gets hold of +your files, the remailer passphrase offers only casual protection for the +remailer keys. If you install a remailer, the remailer passphrase must be +different from your private passphrases. + +Note that nym.alias.net style nym-servers are trivially breakable by an +adversary performing a long-term intersection attack. Discussion of +these attacks can be found in section 4.2 of The Pynchon Gate, by +Sassaman, Cohen, and Mathewson, 2005. Use of Type I remailers for any +purpose is discouraged. + + +Copyright: +--------- + +Mixmaster may be redistributed and modified under certain conditions. This +software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +either express or implied. See the file COPYRIGHT for details. + +A license is required to use the IDEA(TM) algorithm for commercial purposes; +see the file idea.txt for details. + +Mixmaster uses the compression library zlib by Jean-loup Gailly and Mark Adler, +the free ncurses library and the regex library by Philip Hazel. This product +includes cryptographic software written by Eric Young (eay@cryptsoft.com). This +product includes software developed by the OpenSSL Project for use in the +OpenSSL Toolkit (http://www.OpenSSL.org/). For some platforms: This product +includes software developed by the University of California, Berkeley and its +contributors. + +Additionally, this software uses code provided by the members of the +Mixmaster development team. The members respectively hold the copyright +to the code in question, having elected to make it available under the +Mixmaster license. + +All trademarks are the property of their respective owners. + +$Id: README 974 2008-03-03 17:40:11Z rabbi $ diff --git a/Src/Makefile.deps b/Src/Makefile.deps @@ -0,0 +1,46 @@ +# Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + +# Mixmaster may be redistributed and modified under certain conditions. +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +# ANY KIND, either express or implied. See the file COPYRIGHT for +# details. + +# $Id: $ + +buffers.o: mix3.h config.h version.h mix.h +chain.o: mix3.h config.h version.h mix.h +chain1.o: mix3.h config.h version.h mix.h pgp.h +chain2.o: mix3.h config.h version.h mix.h +chain3.o: mix3.h config.h version.h mix.h +compress.o: mix3.h config.h version.h mix.h +crypto.o: mix3.h config.h version.h mix.h crypto.h +dllmain.o: mix3.h config.h version.h mix.h +dummy.o: mix3.h config.h version.h mix.h +keymgt.o: mix3.h config.h version.h mix.h +mail.o: mix3.h config.h version.h mix.h +maildir.o: mix3.h config.h version.h mix.h +main.o: mix3.h config.h version.h mix.h +menu.o: menu.h mix3.h config.h version.h mix.h +menunym.o: menu.h mix3.h config.h version.h mix.h +menusend.o: menu.h mix3.h config.h version.h mix.h +menuutil.o: menu.h mix3.h config.h version.h mix.h +mime.o: mix3.h config.h version.h mix.h +mix.o: mix3.h config.h version.h mix.h menu.h +nym.o: mix3.h config.h version.h mix.h pgp.h +pgp.o: mix3.h config.h version.h mix.h pgp.h +pgpcreat.o: mix3.h config.h version.h mix.h pgp.h crypto.h +pgpdata.o: mix3.h config.h version.h mix.h pgp.h crypto.h +pgpdb.o: mix3.h config.h version.h mix.h pgp.h +pgpget.o: mix3.h config.h version.h mix.h pgp.h crypto.h +mpgp.o: mix3.h config.h version.h mix.h pgp.h +pool.o: mix3.h config.h version.h mix.h +random.o: mix3.h config.h version.h mix.h crypto.h +rem.o: mix3.h config.h version.h mix.h +rem1.o: mix3.h config.h version.h mix.h +rem2.o: mix3.h config.h version.h mix.h +rem3.o: mix3.h config.h version.h mix.h +remailer.o: mix.h +rfc822.o: mix3.h config.h version.h mix.h +rndseed.o: mix3.h config.h version.h mix.h +stats.o: mix3.h config.h version.h mix.h +util.o: mix3.h config.h version.h mix.h diff --git a/Src/Makefile.in b/Src/Makefile.in @@ -0,0 +1,83 @@ +# Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + +# Mixmaster may be redistributed and modified under certain conditions. +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +# ANY KIND, either express or implied. See the file COPYRIGHT for +# details. + +# $Id: Makefile.in 647 2003-10-25 23:34:13Z weasel $ + +# Edit according to the libraries you want to use: +INC = %INC +DEF = %DEF -DUSE_SOCK %MIXDIR +LIBS = %LIBS +LDFLAGS = %LDFLAGS + +OPT = -g -Wall +# OPT = -g -pg -Wall -DDEBUG +# OPT = -O2 -Wall + +CFLAGS = $(INC) $(DEF) $(OPT) +CC = gcc +AR = ar rc +RANLIB = ranlib +#MAKE = make + +OBJ = mix.o rem.o rem1.o rem2.o chain.o chain1.o chain2.o nym.o pgp.o pgpdb.o pgpdata.o pgpget.o pgpcreat.o pool.o mail.o rfc822.o mime.o keymgt.o compress.o stats.o crypto.o random.o util.o buffers.o maildir.o parsedate.tab.o + +MIXOBJ = rndseed.o menu.o menusend.o menunym.o menuutil.o menustats.o +NOMENUOBJ = rndseed.o dummy.o +WINOBJ = winmain.o winutil.o + +all: mixmaster + +mixmaster: $(OBJ) $(MIXOBJ) main.o $(LIBS) + $(CC) $(OBJ) $(MIXOBJ) main.o $(LIBS) $(LDFLAGS) -o mixmaster + +libmix.a: $(OBJ) $(MIXOBJ) dllmain.o + $(AR) libmix.a $(OBJ) $(MIXOBJ) dllmain.o + +libmix32.a: libmix.a mixlib.def + dllwrap --dllname mixlib.dll --def mixlib.def --output-lib libmix32.a libmix.a zlib-1.1.4/libz.a pcre-2.08/libpcre.a openssl/libeay32.a -lwsock32 + +dllmix: main.o libmix32.a + $(CC) main.o libmix32.a -o dllmix + +winmix.exe: $(WINOBJ) libmix32.a + $(CC) $(WINOBJ) libmix32.a -lgdi32 -luser32 $(LDFLAGS) -o mixmaster.exe + +winmix: winmenu.res #winmix.exe + rsrc winmenu.res mixmaster.exe + +winmenu.o: winmenu.rc winmenu.h + windres winmenu.rc winmenu.o + +remailer: $(OBJ) $(NOMENUOBJ) remailer.o $(LIBS) + $(CC) $(OBJ) $(NOMENUOBJ) remailer.o $(LIBS) $(LDFLAGS) -o remailer + +mpgp: $(OBJ) $(NOMENUOBJ) mpgp.o $(LIBS) + $(CC) $(OBJ) $(NOMENUOBJ) mpgp.o $(LIBS) $(LDFLAGS) -o mpgp + +test: $(OBJ) test.o $(NOMENUOBJ) $(LIBS) + $(CC) $(OBJ) test.o $(NOMENUOBJ) $(LIBS) $(LDFLAGS) -o test + +clean: + -rm -f *.o *.a *.res *~ mixmaster mix *.exe remailer test mpgp core gmon.out + +allclean: clean + -rm -f Makefile + +distclean: allclean + +ci: clean + cd ~/src/mix3; ci -l * Mix/* Mix/Src/*; echo + +parsedate.tab.c: parsedate.y + @echo Expect 6 shift/reduce conflicts + bison parsedate.y + +parsedate: parsedate.tab.c + gcc -DTEST parsedate.tab.c -o parsedate + + +include Makefile.deps diff --git a/Src/buffers.c b/Src/buffers.c @@ -0,0 +1,816 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Dynamically allocated buffers + $Id: buffers.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> +#ifdef WIN32 +#include <io.h> +#endif /* WIN32 */ +#include <assert.h> +#ifdef POSIX +#include <unistd.h> +#endif /* POSIX */ + +static void fail(void) +{ + errlog(ERRORMSG, "Out of memory!\n"); + abort(); +} + +#define space 128 /* allocate some additional space */ + +static void alloc(BUFFER *b) +{ + b->data = malloc(space); + if (b->data == NULL) + fail(); + b->data[0] = 0; + b->size = space; +} + +#undef buf_new /* DEBUG */ +BUFFER *buf_new(void) +{ + BUFFER *b; + + b = malloc(sizeof(BUFFER)); + if (b == NULL) + fail(); + alloc(b); + b->length = 0; + b->ptr = 0; + b->sensitive = 0; + + return (b); +} + +#ifdef DEBUG +static void sanity_check(BUFFER *b) +{ + assert(b != NULL); + assert(b->size > 0); + assert(b->data != NULL); + assert(b->length >= 0 && b->length < b->size); + assert(b->ptr >= 0 && b->ptr <= b->length); +} +#else /* not DEBUG */ +#define sanity_check(arg) +#endif /* else not DEBUG */ + +int buf_reset(BUFFER *buffer) +{ + sanity_check(buffer); + + buffer->length = 0; + buffer->ptr = 0; + if (buffer->sensitive) + memset(buffer->data, 0, buffer->size); + free(buffer->data); + alloc(buffer); + return (0); +} + +int buf_free(BUFFER *buffer) +{ + int err = 0; + + if (buffer->sensitive) + memset(buffer->data, 0, buffer->size); + free(buffer->data); + free(buffer); + return (err); +} + +int buf_clear(BUFFER *buffer) +{ + sanity_check(buffer); + buffer->data[0] = '\0'; + buffer->length = 0; + buffer->ptr = 0; + return (0); +} + +int buf_append(BUFFER *buffer, byte *msg, int len) +{ + assert(len >= 0); + sanity_check(buffer); + + if (buffer->length + len >= buffer->size) { + register byte *new; + register long newsize; + + newsize = 2 * buffer->length; /* double buffer size */ + if (newsize < buffer->length + len + space) + newsize = buffer->length + len + space; + new = malloc(newsize); + if (new == NULL) + fail(); + memcpy(new, buffer->data, buffer->length); + if (buffer->sensitive) + memset(buffer->data, 0, buffer->size); + free(buffer->data); + buffer->data = new; + buffer->size = newsize; + } + if (msg != NULL) + memcpy(buffer->data + buffer->length, msg, len); + buffer->length += len; + + buffer->data[buffer->length] = 0; + return (0); +} + +int buf_appendrnd(BUFFER *to, int n) +{ + buf_append(to, NULL, n); + rnd_bytes(to->data + to->length - n, n); + return (0); +} + +int buf_appendzero(BUFFER *to, int n) +{ + buf_append(to, NULL, n); + memset(to->data + to->length - n, 0, n); + return (0); +} + +int buf_setrnd(BUFFER *b, int n) +{ + buf_prepare(b, n); + rnd_bytes(b->data, n); + return (0); +} + +int buf_cat(BUFFER *to, BUFFER *from) +{ + return (buf_append(to, from->data, from->length)); +} + +int buf_set(BUFFER *to, BUFFER *from) +{ + buf_reset(to); + return (buf_cat(to, from)); +} + +int buf_appendc(BUFFER *to, byte b) +{ + return (buf_append(to, &b, 1)); +} + +int buf_rest(BUFFER *to, BUFFER *from) +{ + assert(from != to); + return (buf_append(to, from->data + from->ptr, from->length - from->ptr)); +} + +int buf_appends(BUFFER *buffer, char *s) +{ + return (buf_append(buffer, s, strlen(s))); +} + +int buf_sets(BUFFER *buffer, char *s) +{ + buf_clear(buffer); + return (buf_appends(buffer, s)); +} + +int buf_setc(BUFFER *buffer, byte c) +{ + buf_clear(buffer); + return (buf_appendc(buffer, c)); +} + +int buf_nl(BUFFER *b) +{ + return (buf_append(b, "\n", 1)); +} + +int buf_vappendf(BUFFER *b, char *fmt, va_list args) +{ + for (; *fmt != '\0'; fmt++) + if (*fmt == '%') { + int lzero = 0; + int longvar = 0; + int len = 0; + + for (;;) { + if (*++fmt == '\0') + return (-1); + if (*fmt == '%') { + buf_appendc(b, '%'); + break; + } else if (*fmt == 'b') { /* extension of printf */ + buf_cat(b, va_arg(args, BUFFER *)); + + break; + } else if (*fmt == 'c') { + buf_appendc(b, va_arg(args, int)); + + break; + } else if (*fmt == 's') { + buf_appends(b, va_arg(args, char *)); + + break; + } else if (*fmt == 'd' || *fmt == 'X') { + int base, val, sign = 0; + BUFFER *out; + + out = buf_new(); + base = *fmt == 'd' ? 10 : 16; + if (longvar) + val = va_arg(args, long); + + else + val = va_arg(args, int); + + if (val < 0) + sign = 1, val = -val; + do { + if (val % base > 9) + buf_appendc(out, val % base - 10 + 'A'); + else + buf_appendc(out, val % base + '0'); + val /= base; + } while (val > 0); + if (sign) + len--; + while (len-- > out->length) + buf_appendc(b, lzero ? '0' : ' '); + if (sign) + buf_appendc(b, '-'); + for (len = out->length - 1; len >= 0; len--) + buf_appendc(b, out->data[len]); + buf_free(out); + break; + } else if (*fmt == 'l') + longvar = 1; + else if (*fmt == '0' && len == 0) + lzero = 1; + else if (isdigit(*fmt)) + len = len * 10 + *fmt - '0'; + else + assert(0); + } + } else + buf_appendc(b, *fmt); + return (0); +} + +int buf_setf(BUFFER *b, char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + buf_clear(b); + ret = buf_vappendf(b, fmt, args); + va_end(args); + return (ret); +} + +int buf_appendf(BUFFER *b, char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = buf_vappendf(b, fmt, args); + va_end(args); + return (ret); +} + +int buf_pad(BUFFER *buffer, int size) +{ + assert(size - buffer->length >= 0); + buf_appendrnd(buffer, size - buffer->length); + return (0); +} + +int buf_prepare(BUFFER *buffer, int size) +{ + buf_clear(buffer); + buf_append(buffer, NULL, size); + return (0); +} + +int buf_read(BUFFER *outmsg, FILE *infile) +{ + char buf[BUFSIZE]; + int n; + int err = -1; + + assert(infile != NULL); + sanity_check(outmsg); + + for (;;) { + n = fread(buf, 1, BUFSIZE, infile); + if (n > 0) + err = 0; + buf_append(outmsg, buf, n); + if (n < BUFSIZE) + break; +#ifdef BUFFER_MAX + if (outmsg->length > BUFFER_MAX) { + errlog(ERRORMSG, "Message file too large. Giving up.\n"); + return (1); + } +#endif /* BUFFER_MAX */ + } + +#ifdef WIN32 + if (isatty(fileno(infile)) && isatty(fileno(stdout))) + printf("\n"); +#endif /* WIN32 */ + + return (err); +} + +int buf_write(BUFFER *buffer, FILE *out) +{ + assert(out != NULL); + sanity_check(buffer); + + return (fwrite(buffer->data, 1, buffer->length, out) == buffer->length + ? 0 : -1); +} + +int buf_write_sync(BUFFER *buffer, FILE *out) +{ + int ret = 0; + + if (buf_write(buffer, out) == -1) { + fclose(out); + return -1; + } + + if (fflush(out) != 0) + ret = -1; + +#ifdef POSIX + /* dir entry not synced */ + if (fsync(fileno(out)) != 0) + ret = -1; +#endif /* POSIX */ + + if (fclose(out) != 0) + ret = -1; + + return ret; +} + +int buf_rewind(BUFFER *buffer) +{ + sanity_check(buffer); + + buffer->ptr = 0; + return (0); +} + +int buf_get(BUFFER *buffer, BUFFER *to, int n) +{ + sanity_check(buffer); + sanity_check(to); + assert(n > 0); + assert(buffer != to); + + buf_clear(to); + if (buffer->length - buffer->ptr < n) + return (-1); + buf_append(to, buffer->data + buffer->ptr, n); + buffer->ptr += n; + return (0); +} + +int buf_getc(BUFFER *buffer) +{ + sanity_check(buffer); + if (buffer->ptr == buffer->length) + return (-1); + else + return (buffer->data[buffer->ptr++]); +} + +void buf_ungetc(BUFFER *buffer) +{ + sanity_check(buffer); + if (buffer->ptr > 0) + buffer->ptr--; +} + +int buf_getline(BUFFER *buffer, BUFFER *line) +{ + register int i; + int ret = 0; + int nl = 0; + + sanity_check(buffer); + + if (line != NULL) + buf_clear(line); + if (buffer->ptr == buffer->length) + return (-1); + + for (i = buffer->ptr; i < buffer->length; i++) { + if (buffer->data[i] > '\r') + continue; + if (buffer->data[i] == '\0' || buffer->data[i] == '\n') { + nl = 1; + break; + } + if (buffer->data[i] == '\r' && + i + 1 <= buffer->length && buffer->data[i + 1] == '\n') { + nl = 2; + break; + } + } + + if (line != NULL) + buf_append(line, buffer->data + buffer->ptr, i - buffer->ptr); + if (i == buffer->ptr) + ret = 1; + buffer->ptr = i + nl; + + return (ret); +} + +int buf_chop(BUFFER *b) +{ + int i; + + sanity_check(b); + + for (i = 0; i < b->length; i++) + if (b->data[i] == '\0' || b->data[i] == '\n' || + (b->data[i] == '\r' && i + 1 < b->length && + b->data[i + 1] == '\n')) + b->length = i; + b->data[b->length] = 0; + return (0); +} + +int buf_isheader(BUFFER *buffer) +{ + BUFFER *line; + long p; + int i; + int err; + int ret; + + line = buf_new(); + p = buffer->ptr; + ret = 0; + err = buf_getline(buffer, line); + if (err != 0) + goto end; + + for (i = 0; i < line->length; i++) { + if (line->data[i] == ' ' || line->data[i] == '\t') + break; + if (line->data[i] == ':') { + ret = 1; + break; + } + } + +end: + buffer->ptr = p; + buf_free(line); + return(ret); +} + +int buf_getheader(BUFFER *buffer, BUFFER *field, BUFFER *content) +{ + BUFFER *line; + long p; + int i; + int err; + + line = buf_new(); + buf_reset(field); + buf_reset(content); + + err = buf_getline(buffer, line); + if (err != 0) + goto end; + + err = -1; + for (i = 0; i < line->length; i++) { + if (line->data[i] == ' ' || line->data[i] == '\t') + break; + if (line->data[i] == ':') { + err = 0; + break; + } + } + if (err == -1 && bufileft(line, "From ")) { + buf_set(field, line); + err = 0; + } + if (err == -1) { + /* badly formatted message -- try to process anyway */ + buf_sets(field, "X-Invalid"); + buf_set(content, line); + err = 0; + goto end; + } + buf_append(field, line->data, i); + if (i < line->length) + i++; + else + err = 1; + while (i < line->length && + (line->data[i] == ' ' || line->data[i] == '\t')) + i++; + buf_append(content, line->data + i, line->length - i); + + for (;;) { + p = buffer->ptr; + if (buf_getline(buffer, line) != 0) + break; + if (line->data[0] != ' ' && line->data[0] != '\t') + break; +#if 1 + buf_nl(content); + buf_cat(content, line); +#else /* end of 1 */ + buf_appendc(content, ' '); + buf_appends(content, line->data + 1); +#endif /* else if not 1 */ + } + buffer->ptr = p; +end: + buf_free(line); + return (err); +} + +int buf_appendheader(BUFFER *buffer, BUFFER *field, BUFFER *content) +{ + return buf_appendf(buffer, "%b: %b\n", field, content); +} + +int buf_lookahead(BUFFER *buffer, BUFFER *line) +{ + long p; + int e; + + p = buffer->ptr; + e = buf_getline(buffer, line); + buffer->ptr = p; + return (e); +} + +int buf_eq(BUFFER *b1, BUFFER *b2) +{ + sanity_check(b1); + sanity_check(b2); + + if (b1->length != b2->length) + return (0); + if (b1->length > 0 && memcmp(b1->data, b2->data, b1->length) != 0) + return (0); + return (1); +} + +int buf_ieq(BUFFER *b1, BUFFER *b2) +{ + int i; + sanity_check(b1); + sanity_check(b2); + + if (b1->length != b2->length) + return (0); + for (i = 0; i < b1->length; i++) + if (tolower(b1->data[i]) != tolower(b2->data[i])) + return (0); + return (1); +} + +void buf_move(BUFFER *dest, BUFFER *src) + /* equivalent to buf_set(dest, src); buf_reset(src); */ +{ + BUFFER temp; + sanity_check(src); + buf_reset(dest); + temp.data = dest->data, temp.size = dest->size; + dest->data = src->data, dest->size = src->size, dest->length = src->length; + src->data = temp.data, src->size = temp.size, src->length = 0; + dest->ptr = 0, src->ptr = 0; +} + +int buf_appendl(BUFFER *b, long l) +{ + buf_appendc(b, (l >> 24) & 255); + buf_appendc(b, (l >> 16) & 255); + buf_appendc(b, (l >> 8) & 255); + buf_appendc(b, l & 255); + return (0); +} + +int buf_appendl_lo(BUFFER *b, long l) +{ + buf_appendc(b, l & 255); + buf_appendc(b, (l >> 8) & 255); + buf_appendc(b, (l >> 16) & 255); + buf_appendc(b, (l >> 24) & 255); + return (0); +} + +long buf_getl(BUFFER *b) +{ + long l; + + if (b->ptr + 4 > b->length) + return (-1); + l = buf_getc(b) << 24; + l += buf_getc(b) << 16; + l += buf_getc(b) << 8; + l += buf_getc(b); + return (l); +} + +long buf_getl_lo(BUFFER *b) +{ + long l; + + if (b->ptr + 4 > b->length) + return (-1); + l = buf_getc(b); + l += buf_getc(b) << 8; + l += buf_getc(b) << 16; + l += buf_getc(b) << 24; + + return (l); +} + +int buf_appendi(BUFFER *b, int i) +{ + buf_appendc(b, (i >> 8) & 255); + buf_appendc(b, i & 255); + return (0); +} + +int buf_appendi_lo(BUFFER *b, int i) +{ + buf_appendc(b, i & 255); + buf_appendc(b, (i >> 8) & 255); + return (0); +} + +int buf_geti(BUFFER *b) +{ + int i; + + if (b->ptr + 2 > b->length) + return (-1); + i = buf_getc(b) << 8; + i += buf_getc(b); + return (i); +} + +int buf_geti_lo(BUFFER *b) +{ + int i; + + if (b->ptr + 2 > b->length) + return (-1); + i = buf_getc(b); + i += buf_getc(b) << 8; + return (i); +} + +int buf_getb(BUFFER *b, BUFFER *p) +{ + long l; + + l = buf_getl(b); + return (buf_get(b, p, l)); +} + +int buf_appendb(BUFFER *b, BUFFER *p) +{ + long l; + + l = p->length; + buf_appendl(b, l); + return (buf_cat(b, p)); +} + +int bufleft(BUFFER *b, char *k) { + return(strleft(b->data, k)); +} + +int bufileft(BUFFER *b, char *k) { + return(strileft(b->data, k)); +} + +int buffind(BUFFER *b, char *k) { + return(strfind(b->data, k)); +} + +int bufifind(BUFFER *b, char *k) { + return(strifind(b->data, k)); +} + +int bufiright(BUFFER *b, char *k) { + int l = strlen(k); + if (l <= b->length) + return (strieq(b->data + b->length - l, k)); + return(0); +} + +int bufeq(BUFFER *b, char *k) { + return(streq(b->data, k)); +} + +int bufieq(BUFFER *b, char *k) { + return(strieq(b->data, k)); +} + +/* void buf_cut_out(BUFFER *buffer, BUFFER *cut_out, BUFFER *rest, + * int from, int len); + * + * Cut a chunk out of the buffer. + * + * Starting with from, len bytes are cut out of buffer. The chunk + * of text that has been cut out is returned in cut_out, the + * remainings of buffer are returned in rest. + * + * This function was added by Gerd Beuster. (gb@uni-koblenz.de) + */ + +void buf_cut_out(BUFFER *buffer, BUFFER *cut_out, BUFFER *rest, + int from, int len){ + + assert((len >= 0) && (from >= 0)); + assert(from+len <= buffer->length); + assert(cut_out != rest); + + buffer->ptr = 0; + if(from > 0) + buf_get(buffer, rest, from); + buf_get(buffer, cut_out, len); + buf_rest(rest, buffer); +} + + +#ifdef DEBUG +/* check for memory leaks */ +#undef malloc +#undef free +void *malloc(size_t size); +void free(void *ptr); +#define max 100000 +static int n=0; +static void *m[max]; +static char *mm[max]; + +void mix3_leaks(void) { + int i, ok=1; + for (i = 0; i < n; i++) + if (m[i]) { + fprintf(stderr, "Leak [%d] %s\n", i, mm[i]); + ok = 0; + } + if (ok) + fprintf(stderr, "No memory leaks.\n"); +} + +void *mix3_malloc(size_t size) { + void *ptr; + if (n == 0) + atexit(mix3_leaks); + ptr = malloc(size); + if (n >= max) abort(); + m[n++] = ptr; + mm[n] = "?"; + return(ptr); +} + +void mix3_free(void *ptr) { + int i; + for (i = 0; i < n; i++) + if (m[i] == ptr) { + m[i] = 0; + break; + } + free(ptr); +} + +BUFFER *mix3_bufnew(char *file, int line, char *func) { + mm[n] = malloc(strlen(file) + strlen(func) + 15); + sprintf(mm[n], "in %s %s:%d", func, file, line); + return(buf_new()); +} +#endif /* DEBUG */ diff --git a/Src/chain.c b/Src/chain.c @@ -0,0 +1,384 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Prepare messages for remailer chain + $Id: chain.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <stdlib.h> + +void clienterr(BUFFER *msgbuf, char *err) +{ + if (msgbuf) { + buf_sets(msgbuf, "Error: "); + buf_appends(msgbuf, err); + } else + errlog(ERRORMSG, "%s\n", err); +} + +void parse_badchains(int badchains[MAXREM][MAXREM], char *file, char *startindicator, REMAILER *remailer, int maxrem) { + int i,j; + FILE *list; + char line[LINELEN]; + + if (!badchains) + return; + + for (i = 0; i < maxrem; i++ ) + for (j = 0; j < maxrem; j++ ) + badchains[i][j] = 0; + list = mix_openfile(TYPE2REL, "r"); + if (list != NULL) { + while (fgets(line, sizeof(line), list) != NULL && + !strleft(line, startindicator)) ; + while (fgets(line, sizeof(line), list) != NULL && + strleft(line, "(")) { + char *left, *right, *tmp; + int lefti, righti; + + left = line + 1; + while (*left == ' ') + left ++; + + tmp = left + 1; + while (*tmp != ' ' && *tmp != '\0' && *tmp != ')') + tmp ++; + if (*tmp == '\0' || *tmp == ')') + /* parsing this line failed */ + continue; + *tmp = '\0'; + + right = tmp+1; + while (*right == ' ') + right ++; + tmp = right + 1; + while (*tmp != ' ' && *tmp != '\0' && *tmp != ')') + tmp ++; + if (*tmp == '\0') + /* parsing this line failed */ + continue; + *tmp = '\0'; + + lefti = -1; + righti = -1; + for (i = 1; i < maxrem; i++) { + if (strcmp(remailer[i].name, left) == 0) + lefti = i; + if (strcmp(remailer[i].name, right) == 0) + righti = i; + } + if (strcmp(left, "*") == 0) + lefti = 0; + if (strcmp(right, "*") == 0) + righti = 0; + + if (lefti == -1 || righti == -1) + /* we don't know about one or both remailers */ + continue; + badchains[lefti][righti] = 1; + } + fclose(list); + /* If some broken chain includes all remailers (*) mark it broken for + * every single remailer - this simplifies handling in other places */ + for (i=1; i < maxrem; i++ ) { + if (badchains[0][i]) + for (j=1; j < maxrem; j++ ) + badchains[j][i] = 1; + if (badchains[i][0]) + for (j=1; j < maxrem; j++ ) + badchains[i][j] = 1; + } + } +} + + +int chain_select(int hop[], char *chainstr, int maxrem, REMAILER *remailer, + int type, BUFFER *feedback) +{ + int len = 0; + int i, j, k; + BUFFER *chain, *selected, *addr; + chain = buf_new(); + selected = buf_new(); + addr = buf_new(); + + if (chainstr == NULL || chainstr[0] == '\0') + buf_sets(chain, CHAIN); + else + buf_sets(chain, chainstr); + + /* put the chain backwards: final hop is in hop[0] */ + + for (i = chain->length; i >= 0; i--) + if (i == 0 || chain->data[i - 1] == ',' + || chain->data[i - 1] == ';' || chain->data[i - 1] == ':') { + for (j = i; isspace(chain->data[j]);) /* ignore whitespace */ + j++; + if (chain->data[j] == '\0') + break; + + if (chain->data[j] == '*') + k = 0; +#if 0 + else if (isdigit(chain->data[j])) + k = atoi(chain->data + j); +#endif /* 0 */ + else { + buf_sets(selected, chain->data + j); + rfc822_addr(selected, addr); + buf_clear(selected); + buf_getline(addr, selected); + if (!selected->length) + buf_sets(selected, chain->data + j); + + for (k = 0; k < maxrem; k++) + if (((remailer[k].flags.mix && type == 0) || + (remailer[k].flags.cpunk && type == 1) || + (remailer[k].flags.newnym && type == 2)) && + (streq(remailer[k].name, selected->data) || + strieq(remailer[k].addr, selected->data) || + (selected->data[0] == '@' && strifind(remailer[k].addr, + selected->data)))) + break; + } + if (k < 0 || k >= maxrem) { + if (feedback != NULL) { + buf_appendf(feedback, "No such remailer: %b", selected); + buf_nl(feedback); + } +#if 0 + k = 0; +#else /* end of 0 */ + len = -1; + goto end; +#endif /* else not 0 */ + } + hop[len++] = k; + if (len >= 20) { /* array passed in is has length 20 */ + if (feedback != NULL) { + buf_appends(feedback, "Chain too long.\n"); + } + break; + } + if (i > 0) + chain->data[i - 1] = '\0'; + } +end: + buf_free(chain); + buf_free(selected); + buf_free(addr); + return len; +} + +int chain_randfinal(int type, REMAILER *remailer, int badchains[MAXREM][MAXREM], int maxrem, int rtype, int chain[], int chainlen, int ignore_constraints_if_necessary) +{ + int randavail; + int i; + int t; + int select[MAXREM]; + int secondtolasthop = (chainlen <= 1 ? -1 : chain[1]); + int constraints_ignored = 0; + + t = rtype; + if (rtype == 2) + t = 1; + +start: + randavail = 0; + /* select a random final hop */ + for (i = 1; i < maxrem; i++) { + select[i] = + ((remailer[i].flags.mix && rtype == 0) || /* remailer supports type */ + (remailer[i].flags.pgp && remailer[i].flags.ek && rtype == 1) || + (remailer[i].flags.newnym && rtype == 2)) && + (remailer[i].info[t].reliability >= 100 * RELFINAL || constraints_ignored ) && /* remailer has sufficient reliability */ + (remailer[i].info[t].latency <= MAXLAT || constraints_ignored ) && /* remailer has low enough latency */ + (remailer[i].info[t].latency >= MINLAT || constraints_ignored ) && /* remailer has high enough latency */ + (type == MSG_NULL || !remailer[i].flags.middle) && /* remailer is not middleman */ + !remailer[i].flags.star_ex && /* remailer is not excluded from random selection */ + (remailer[i].flags.post || type != MSG_POST) && /* remailer supports post when this is a post */ + ((secondtolasthop == -1) || !badchains[secondtolasthop][i]); + /* we only have hop or the previous one can send to this (may be random) */ + randavail += select[i]; + } + + for (i = 1; i <= DISTANCE; i++) + if (i < chainlen && select[chain[i]] && chain[i]) { + select[chain[i]] = 0; + randavail--; + } + + assert(randavail >= 0); + if (randavail == 0) { + if (ignore_constraints_if_necessary && !constraints_ignored) { + errlog(WARNING, "No reliable remailers. Ignoring for randhop\n"); + constraints_ignored = 1; + goto start; + }; + i = -1; + } else { + do + i = rnd_number(maxrem - 1) + 1; + while (!select[i]); + } + return (i); +} + +int chain_rand(REMAILER *remailer, int badchains[MAXREM][MAXREM], int maxrem, + int thischain[], int chainlen, int t, int ignore_constraints_if_necessary) + /* set random chain. returns 0 if not random, 1 if random, -1 on error */ +/* t... 0 for mixmaster Type II + * 1 for cypherpunk Type I + */ +{ + int hop; + int err = 0; + int constraints_ignored = 0; + + assert(t == 0 || t == 1); + +start: + for (hop = 0; hop < chainlen; hop++) + if (thischain[hop] == 0) { + int select[MAXREM]; + int randavail = 0; + int i; + + err = 1; + if (hop > 0) + assert(thischain[hop-1]); /* we already should have chosen a remailer after this one */ + for (i = 1; i < maxrem; i++) { + select[i] = ((remailer[i].flags.mix && t == 0) || /* remailer supports type */ + (remailer[i].flags.pgp && remailer[i].flags.ek && t == 1)) && + (remailer[i].info[t].reliability >= 100 * MINREL || constraints_ignored ) && /* remailer has sufficient reliability */ + (remailer[i].info[t].latency <= MAXLAT || constraints_ignored ) && /* remailer has low enough latency */ + (remailer[i].info[t].latency >= MINLAT || constraints_ignored ) && /* remailer has high enough latency */ + !remailer[i].flags.star_ex && /* remailer is not excluded from random selection */ + !badchains[i][0] && !badchains[i][thischain[hop-1]] && /* remailer can send to the next one */ + (hop == chainlen-1 || !badchains[thischain[hop+1]][i]); + /* we are at the first hop or the previous one can send to this (may be random) */ + randavail += select[i]; + } + + for (i = hop - DISTANCE; i <= hop + DISTANCE; i++) + if (i >= 0 && i < chainlen && select[thischain[i]] && thischain[i]) { + select[thischain[i]] = 0; + randavail--; + } + + + assert(randavail >= 0); + if (randavail < 1) { + if (ignore_constraints_if_necessary && !constraints_ignored) { + errlog(WARNING, "No reliable remailers. Ignoring for randhop\n"); + constraints_ignored = 1; + goto start; + }; + err = -1; + goto end; + } + do + thischain[hop] = rnd_number(maxrem - 1) + 1; + while (!select[thischain[hop]]); + } +end: + return (err); +} + +int mix_encrypt(int type, BUFFER *message, char *chainstr, int numcopies, + BUFFER *chainlist) +{ + return (mix2_encrypt(type, message, chainstr, numcopies, 0, chainlist)); +} + +/* float chain_reliablity(char *chain, int chaintype, + char *reliability_string); + * + * Compute reliablity of a chain. + * + * We get the reliablity of the chain by multiplying the reliablity of + * every remailer in the chain. The return value is the reliablity of + * the chain, or a negative number if the reliablity can not be + * calculated. There are two reasons why may not be able to calculated + * the reliablity: A remailer in the chain is selected randomly, or we + * don't have statistics about one of the remailers in the chain. + * remailer_type indicates the remailer type: + * 0 = Mixmaster, 1 = Cypherpunk + * + * If reliability_string is non-NULL, the reliability is also returned + * as a string in this variable. The size of the string must be at + * least 9 characters! + * + * This function has been added by Gerd Beuster. (gb@uni-koblenz.de) + *--------------------------------------------------------------------*/ + +float chain_reliability(char *chain, int chaintype, + char *reliability_string){ + + float acc_reliability = 1; /* Accumulated reliablity */ + char *name_start, *name_end; /* temporary pointers used + in string scanning */ + char remailer_name[20]; /* The length of the array is taken from mix3.h. */ + int error = 0; + int maxrem; + int i; + int previous = -1; + REMAILER remailer[MAXREM]; + int badchains[MAXREM][MAXREM]; + + /* chaintype 0=mix 1=ek 2=newnym */ + assert((chaintype == 0) || (chaintype == 1)); + maxrem = (chaintype == 0 ? mix2_rlist(remailer, badchains) : t1_rlist(remailer, badchains)); + + /* Dissect chain */ + name_start = chain; + name_end = chain; + while(*name_end != '\0'){ /* While string not scanned completely */ + do /* Get next remailer */ + name_end+=sizeof(char); + while( (*name_end != ',') && (*name_end != '\0')); + strncpy(remailer_name, name_start, + (name_end - name_start) / sizeof(char) + 1*sizeof(char)); + remailer_name[name_end-name_start]='\0'; + /* Lookup reliablity for remailer remailer_name */ + for(i=0; + (i < maxrem) && (strcmp(remailer[i].name, remailer_name) != 0); + i++); + if(!strcmp(remailer[i].name, remailer_name)) { /* Found it! */ + acc_reliability *= + ((float) remailer[i].info[chaintype].reliability) / 10000; + if (previous != -1) { + if (badchains[previous][i] || badchains[0][i]) + acc_reliability = 0; + } + previous = i; + } else + error = 1; /* Did not find this remailer. We can't calculate + the reliablity for the whole chain. */ + name_start = name_end+sizeof(char); + } + + if(error || (name_start==name_end)) + acc_reliability = -1; + + /* Convert reliability into string, if appropriate */ + if(reliability_string){ + if(acc_reliability < 0) + sprintf(reliability_string, " n/a "); + else{ + sprintf(reliability_string, "%6.2f", acc_reliability*100); + *(reliability_string+6*sizeof(char)) = '%'; + } + } + + return acc_reliability; +} + diff --git a/Src/chain1.c b/Src/chain1.c @@ -0,0 +1,301 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Encrypt message for Cypherpunk remailer chain + $Id: chain1.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include "pgp.h" +#include <string.h> +#include <ctype.h> + +#define N(X) (isdigit(X) ? (X)-'0' : 0) + +int t1_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM]) +{ + FILE *list, *excl; + int i, listed = 0; + int n = 0; + char line[2 * LINELEN], l2[LINELEN], name[LINELEN], *flags; + BUFFER *starex; + + starex = buf_new(); + excl = mix_openfile(STAREX, "r"); + if (excl != NULL) { + buf_read(starex, excl); + fclose(excl); + } + + list = mix_openfile(TYPE1LIST, "r"); + if (list == NULL) { + buf_free(starex); + return (-1); + } + + while (fgets(line, sizeof(line), list) != NULL && n < MAXREM) { + if (strleft(line, "$remailer") && + strchr(line, '<') && strchr(line, '>') && + strchr(line, '{') && strchr(line, '{') + 4 < strchr(line, '}')) { + if (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; + if (line[strlen(line) - 1] == '\r') + line[strlen(line) - 1] = '\0'; + while (line[strlen(line) - 1] == ' ') + line[strlen(line) - 1] = '\0'; + if (line[strlen(line) - 1] != ';' + && fgets(l2, sizeof(l2), list) != NULL) + strcatn(line, l2, LINELEN); + flags = strchr(line, '>'); + strncpy(name, strchr(line, '{') + 2, + strchr(line, '}') - strchr(line, '{') - 3); + name[strchr(line, '}') - strchr(line, '{') - 3] = '\0'; + name[20] = '\0'; + + for (i = 1; i <= n; i++) + if (streq(name, remailer[i].name)) + break; + if (i > n) { + /* not in mix list */ + n++; + strcpy(remailer[i].name, name); + strncpy(remailer[i].addr, strchr(line, '<') + 1, + strchr(line, '>') - strchr(line, '<')); + remailer[i].addr[strchr(line, '>') - strchr(line, '<') - 1] + = '\0'; + remailer[i].flags.mix = 0; + remailer[i].flags.post = strifind(flags, " post"); + } + remailer[i].flags.cpunk = strfind(flags, " cpunk"); + remailer[i].flags.pgp = strfind(flags, " pgp"); + remailer[i].flags.pgponly = strfind(flags, " pgponly"); + remailer[i].flags.latent = strfind(flags, " latent"); + remailer[i].flags.middle = strfind(flags, " middle"); + remailer[i].flags.ek = strfind(flags, " ek"); + remailer[i].flags.esub = strfind(flags, " esub"); + remailer[i].flags.newnym = strfind(flags, " newnym"); + remailer[i].flags.nym = strfind(flags, " nym"); + remailer[i].info[1].reliability = 0; + remailer[i].info[1].latency = 0; + remailer[i].info[1].history[0] = '\0'; + remailer[i].flags.star_ex = bufifind(starex, name); + } + if (strleft(line, + "-----------------------------------------------------------------------")) + break; + } + n++; /* ?? */ + while (fgets(line, sizeof(line), list) != NULL) { + if (strlen(line) >= 72 && strlen(line) <= 73) + for (i = 1; i < n; i++) + if (strleft(line, remailer[i].name) && + line[strlen(remailer[i].name)] == ' ') { + strncpy(remailer[i].info[1].history, line + 42, 12); + remailer[i].info[1].history[12] = '\0'; + remailer[i].info[1].reliability = 10000 * N(line[64]) + + 1000 * N(line[65]) + 100 * N(line[66]) + + 10 * N(line[68]) + N(line[69]); + remailer[i].info[1].latency = 36000 * N(line[55]) + + 3600 * N(line[56]) + 600 * N(line[58]) + + 60 * N(line[59]) + 10 * N(line[61]) + + N(line[62]); + listed++; + } + } + fclose(list); + parse_badchains(badchains, TYPE1LIST, "Broken type-I remailer chains", remailer, n); + if (listed < 4) /* we have no valid reliability info */ + for (i = 1; i < n; i++) + remailer[i].info[1].reliability = 10000; + +#ifdef USE_PGP + pgp_rlist(remailer, n); +#endif /* USE_PGP */ + buf_free(starex); + return (n); +} + +int t1_ek(BUFFER *key, BUFFER *seed, int num) +{ + buf_reset(key); + buf_appendc(key, (byte) num); + buf_cat(key, seed); + digest_md5(key, key); + encode(key, 0); +#ifdef DEBUG + fprintf(stderr, "passphrase=%s (%2X%2X%2X%2X %d)\n", key->data, + seed->data[0], seed->data[1], seed->data[2], seed->data[3], num); +#endif /* DEBUG */ + return (0); +} + +int t1_encrypt(int type, BUFFER *message, char *chainstr, int latency, + BUFFER *ek, BUFFER *feedback) +{ + BUFFER *b, *rem, *dest, *line, *field, *content; + REMAILER remailer[MAXREM]; + int badchains[MAXREM][MAXREM]; + int maxrem, chainlen = 0; + int chain[20]; + int hop; + int hashmark = 0; + int err = 0; + + b = buf_new(); + rem = buf_new(); + dest = buf_new(); + line = buf_new(); + field = buf_new(); + content = buf_new(); + + maxrem = t1_rlist(remailer, badchains); + if (maxrem < 1) { + clienterr(feedback, "No remailer list!"); + err = -1; + goto end; + } + chainlen = chain_select(chain, chainstr, maxrem, remailer, 1, line); + if (chainlen < 1) { + if (line->length) + clienterr(feedback, line->data); + else + clienterr(feedback, "Invalid remailer chain!"); + err = -1; + goto end; + } + if (chain[0] == 0) + chain[0] = chain_randfinal(type, remailer, badchains, maxrem, 1, chain, chainlen, 0); + + if (chain[0] == -1) { + clienterr(feedback, "Invalid remailer chain!"); + err = -1; + goto end; + } + if (chain_rand(remailer, badchains, maxrem, chain, chainlen, 1, 0) == -1) { + clienterr(feedback, "No reliable remailers!"); + err = -1; + goto end; + } + while (buf_getheader(message, field, content) == 0) { + hdr_encode(content, 0); + if (type == MSG_POST && bufieq(field, "newsgroups") && + remailer[chain[0]].flags.post) { + buf_appendf(dest, "Anon-Post-To: %b\n", content); + } else if (type == MSG_MAIL && bufieq(field, "to")) { + buf_appendf(dest, "Anon-To: %b\n", content); + } else { + /* paste header */ + if (type == MSG_POST && bufieq(field, "newsgroups")) + buf_appendf(dest, "Anon-To: %s\n", MAILtoNEWS); + if (hashmark == 0) { + buf_appends(b, "##\n"); + hashmark = 1; + } + buf_appendheader(b, field, content); + } + } + buf_nl(b); + buf_rest(b, message); + buf_move(message, b); + + if (type != MSG_NULL && dest->length == 0) { + clienterr(feedback, "No destination address!"); + err = -1; + goto end; + } + if (type == MSG_NULL) { + buf_sets(dest, "Null:\n"); + } + for (hop = 0; hop < chainlen; hop++) { + if (hop == 0) { + buf_sets(b, "::\n"); + buf_cat(b, dest); + } else { + buf_sets(b, "::\nAnon-To: "); + buf_appends(b, remailer[chain[hop - 1]].addr); + buf_nl(b); + } + if (remailer[chain[hop]].flags.latent && latency > 0) + buf_appendf(b, "Latent-Time: +%d:00r\n", latency); + if (ek && remailer[chain[hop]].flags.ek) { + t1_ek(line, ek, hop); + buf_appendf(b, "Encrypt-Key: %b\n", line); + } + buf_nl(b); + buf_cat(b, message); +#ifdef USE_PGP + if (remailer[chain[hop]].flags.pgp) { + buf_clear(message); + buf_clear(rem); + buf_setf(rem, "<%s>", remailer[chain[hop]].addr); + err = pgp_encrypt(PGP_ENCRYPT | PGP_REMAIL | PGP_TEXT, b, rem, + NULL, NULL, NULL, NULL); + if (err < 0) { + buf_setf(line, "No PGP key for remailer %s!\n", + remailer[chain[hop]].name); + clienterr(feedback, line->data); + goto end; + } + buf_appends(message, "::\nEncrypted: PGP\n\n"); + buf_cat(message, b); + } else +#endif /* USE_PGP */ + { + if (remailer[chain[hop]].flags.pgponly) { + buf_setf(line, "PGP encryption needed for remailer %s!\n", + remailer[chain[hop]].name); + clienterr(feedback, line->data); + goto end; + } + buf_move(message, b); + } + if (ek && remailer[chain[hop]].flags.ek) + buf_appends(message, "\n**\n"); + } + buf_clear(b); + if (chainlen == 0) { + buf_appends(b, "::\n"); + buf_cat(b, dest); + } else { + buf_appendf(b, "%s: %s\n", ek ? "::\nAnon-To" : "To", + remailer[chain[chainlen - 1]].addr); + } + buf_nl(b); + buf_cat(b, message); + buf_move(message, b); +end: + buf_free(b); + buf_free(rem); + buf_free(dest); + buf_free(line); + buf_free(field); + buf_free(content); + return (err); +} + +#ifdef USE_PGP +int t1_getreply(BUFFER *msg, BUFFER *ek, int len) +{ + BUFFER *key, *decrypt; + int err = -1; + int hop = 0; + + key = buf_new(); + decrypt = buf_new(); + + do { + t1_ek(key, ek, hop); + buf_set(decrypt, msg); + if (pgp_decrypt(decrypt, key, NULL, NULL, NULL) == 0 + && decrypt->data != NULL) + err = 0, buf_move(msg, decrypt); + } + while (hop++ < len); + return (err); +} + +#endif /* USE_PGP */ diff --git a/Src/chain2.c b/Src/chain2.c @@ -0,0 +1,685 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Encrypt message for Mixmaster chain + $Id: chain2.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <ctype.h> +#include <assert.h> + +#define N(X) (isdigit(X) ? (X)-'0' : 0) + +int prepare_type2list(BUFFER *out) +{ + FILE *list; + char line[LINELEN], name[LINELEN], addr[LINELEN], keyid[LINELEN], + version[LINELEN], flags[LINELEN], createdstr[LINELEN], expiresstr[LINELEN]; + int assigned; + time_t created, expires; + + list = mix_openfile(PUBRING, "r"); + if (list == NULL) + return (-1); + while (fgets(line, sizeof(line), list) != NULL) { + if (strleft(line, begin_key)) { + while (fgets(line, sizeof(line), list) != NULL && + !strleft(line, end_key)) ; + } else if (strlen(line) > 36 && line[0] != '#') { + assigned = sscanf(line, "%127s %127s %127s %127s %127s %127s %127s", + name, addr, keyid, version, flags, createdstr, expiresstr); + if (assigned < 4) + continue; + if (assigned >= 6) { + created = parse_yearmonthday(createdstr); + if (created == 0 || created == -1) { + errlog(WARNING, "Cannot parse creation date of key %s.\n", keyid); + continue; + }; + if (created > time(NULL)) { + errlog(WARNING, "Key %s created in the future.\n", keyid); + continue; + }; + } + if (assigned >= 7) { + expires = parse_yearmonthday(expiresstr); + if (expires == 0 || expires == -1) { + errlog(WARNING, "Cannot parse expiration date of key %s.\n", keyid); + continue; + }; + if (expires < time(NULL)) { + errlog(WARNING, "Key %s has expired.\n", keyid); + continue; + }; + } + buf_appends(out, line); + } + } + fclose(list); + return (0); +} + +int mix2_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM]) +{ + FILE *list, *excl; + int n, i, listed = 0; + + char line[LINELEN], name[LINELEN], addr[LINELEN], keyid[LINELEN], + version[LINELEN], flags[LINELEN], createdstr[LINELEN], expiresstr[LINELEN]; + int assigned; + time_t created, expires; + BUFFER *starex; + + starex = buf_new(); + excl = mix_openfile(STAREX, "r"); + if (excl != NULL) { + buf_read(starex, excl); + fclose(excl); + } + + list = mix_openfile(PUBRING, "r"); + if (list == NULL) { + buf_free(starex); + return (-1); + } + for (n = 1; fgets(line, sizeof(line), list) != NULL && n < MAXREM;) + if (strleft(line, begin_key)) { + while (fgets(line, sizeof(line), list) != NULL && + !strleft(line, end_key)) ; + } else if (strlen(line) > 36 && line[0] != '#') { + flags[0] = '\0'; + assigned = sscanf(line, "%127s %127s %127s %127s %127s %127s %127s", + name, addr, keyid, version, flags, createdstr, expiresstr); + if (assigned < 4) + continue; + if (assigned >= 6) { + created = parse_yearmonthday(createdstr); + if (created == 0 || created == -1) { + errlog(WARNING, "Cannot parse creation date of key %s.\n", keyid); + continue; + }; + if (created > time(NULL)) { + errlog(WARNING, "Key %s created in the future.\n", keyid); + continue; + }; + } + if (assigned >= 7) { + expires = parse_yearmonthday(expiresstr); + if (expires == 0 || expires == -1) { + errlog(WARNING, "Cannot parse expiration date of key %s.\n", keyid); + continue; + }; + if (expires < time(NULL)) { + errlog(WARNING, "Key %s has expired.\n", keyid); + continue; + }; + } + strncpy(remailer[n].name, name, sizeof(remailer[n].name)); + remailer[n].name[sizeof(remailer[n].name) - 1] = '\0'; + strncpy(remailer[n].addr, addr, sizeof(remailer[n].addr)); + remailer[n].addr[sizeof(remailer[n].addr) - 1] = '\0'; + remailer[n].flags.mix = 1; + remailer[n].flags.cpunk = 0; + remailer[n].flags.nym = 0; + remailer[n].flags.newnym = 0; + id_decode(keyid, remailer[n].keyid); + remailer[n].version = N(version[0]); + remailer[n].flags.compress = strfind(flags, "C"); + remailer[n].flags.post = strfind(flags, "N"); + remailer[n].flags.middle = strfind(flags, "M"); + remailer[n].info[0].reliability = 0; + remailer[n].info[0].latency = 0; + remailer[n].info[0].history[0] = '\0'; + remailer[n].flags.star_ex = bufifind(starex, name); + n++; + } + fclose(list); + list = mix_openfile(TYPE2REL, "r"); + if (list != NULL) { + while (fgets(line, sizeof(line), list) != NULL && + !strleft(line, "--------------------------------------------")) { + if (strleft(line, "Last update:")) { + int generated; + int now = time(NULL); + char *tmp = line + strlen("Last update:") + 1; + generated = parsedate(tmp); + if (generated == -1) { + /* For some weird reason, this isn't rfc822 */ + if (strleft(tmp, "Mon") || + strleft(tmp, "Tue") || + strleft(tmp, "Wed") || + strleft(tmp, "Thu") || + strleft(tmp, "Fri") || + strleft(tmp, "Sat") || + strleft(tmp, "Sun")) + tmp += 3; + generated = parsedate(tmp); + } + now = time(NULL); + if (generated != -1 && generated < now - SECONDSPERDAY) + errlog(WARNING, "Remailer Reliability Statistics are older than one day (check your clock?).\n"); + if (generated != -1 && generated > now) + errlog(WARNING, "Remailer Reliability Statistics are from the future (check your clock?).\n"); + } + }; + while (fgets(line, sizeof(line), list) != NULL && + !strleft(line, "</PRE>")) + if (strlen(line) >= 44 && strlen(line) <= 46) + for (i = 1; i < n; i++) + if (strleft(line, remailer[i].name) && + line[strlen(remailer[i].name)] == ' ') { + strncpy(remailer[i].info[0].history, line + 15, 12); + remailer[i].info[0].history[12] = '\0'; + remailer[i].info[0].reliability = 10000 * N(line[37]) + + 1000 * N(line[38]) + 100 * N(line[39]) + + 10 * N(line[41]) + N(line[42]); + remailer[i].info[0].latency = 36000 * N(line[28]) + + 3600 * N(line[29]) + 600 * N(line[31]) + + 60 * N(line[32]) + 10 * N(line[34]) + + N(line[35]); + listed++; + } + fclose(list); + } + + parse_badchains(badchains, TYPE2REL, "Broken type-II remailer chains", remailer, n); + if (listed < 4) /* we have no valid reliability info */ + for (i = 1; i < n; i++) + remailer[i].info[0].reliability = 10000; + buf_free(starex); + return (n); +} + +static int send_packet(int numcopies, BUFFER *packet, int chain[], + int chainlen, int packetnum, int numpackets, + BUFFER *mid, REMAILER remailer[], int badchains[MAXREM][MAXREM], + int maxrem, char *redirect_to, int ignore_constraints_if_necessary, + BUFFER *feedback) +/* + * Puts a mix packet in the pool. + * + * numcopies ... how often to put this packet into the pool + * i.e. send it. required that random remailers are in the chain. + * packet ... the payload, 10240 bytes in size. + * chain ... the chain to send this message along + * chainlen ... length of the chain + * packetnum ... in multi-packet messages (fragmented) the serial of this packet + * numpackets ... the total number of packets + * mid ... the message ID (required for fragmented packets + * remailer ... information about remailers, their reliabilities, capabilities, etc. + * badchains ... broken chain information + * maxrem ... the number of remailers in remailer[] and badchains[] + * redirect_to ... if this is not-null it needs to be an email address. + * in this case packet needs to be not only the body, but a + * complete mixmaster packet of 20480 bytes in size (20 headers + body). + * the chain given is prepended to the one already encrypted in + * the existing message. If this exceeds the allowed 20 hops in total + * the message is corrupted, the last node will realize this. + * This is useful if you want to reroute an existing mixmaster message + * that has foo as the next hop via a chain so that the packet will + * actually flow hop1,hop2,hop3,foo,.... + * ignore_constraints_if_necessary .. to be used when randhopping messages. + * if a chain can not be constructed otherwhise, maxlat, minlat, + * and minrel are ignored. + * feedback ... a buffer to write feedback to + */ +{ + BUFFER *pid, *out, *header, *other, *encrypted, *key, *body; + BUFFER *iv, *ivarray, *temp; + BUFFER *pubkey; + char addr[LINELEN]; + int thischain[20]; + int hop; + int c, i; + int timestamp = 0; + int israndom = 0; + int err = 1; + + body = buf_new(); + pid = buf_new(); + out = buf_new(); + header = buf_new(); + other = buf_new(); + key = buf_new(); + encrypted = buf_new(); + iv = buf_new(); + ivarray = buf_new(); + temp = buf_new(); + + if (redirect_to != NULL) { + assert(packet->length == 20480); + buf_append(header, packet->data, 10240); + buf_append(temp, packet->data + 10240, 10240); + buf_clear(packet); + buf_cat(packet, temp); + } else + assert(packet->length == 10240); + + buf_setrnd(pid, 16); + + for (c = 0; c < numcopies; c++) { + buf_set(body, packet); + + for (hop = 0; hop < chainlen; hop++) + thischain[hop] = chain[hop]; + + israndom = chain_rand(remailer, badchains, maxrem, thischain, chainlen, 0, ignore_constraints_if_necessary); + if (israndom == -1) { + err = -1; + clienterr(feedback, "No reliable remailers!"); + } + if ((numcopies > 1 || numpackets > 1) && !israndom && (chainlen != 1)) { + clienterr(feedback, + "Multi-packet message without random remailers!"); + err = -1; + goto end; + } + for (hop = 0; hop < chainlen; hop++) { + switch (remailer[thischain[hop]].version) { + case 2: + case 3: /* not implemented yet; fall back to version 2 */ + /* create header chart to be encrypted with the session key */ + if (numcopies > 1 && hop == 0 && redirect_to == NULL) + buf_set(encrypted, pid); /* same ID only at final hop */ + else + buf_setrnd(encrypted, 16); + buf_setrnd(key, 24); /* key for encrypting the body */ + buf_cat(encrypted, key); + buf_setrnd(iv, 8); /* IV for encrypting the body */ + + if (hop > 0 || redirect_to != NULL) { + /* IVs for header chart encryption */ + buf_setrnd(ivarray, 18 * 8); + buf_cat(ivarray, iv); /* 19th IV equals the body IV */ + + buf_appendc(encrypted, 0); + buf_cat(encrypted, ivarray); + memset(addr, 0, 80); + if (hop == 0) { + assert(redirect_to != NULL); + strncpy(addr, redirect_to, 80); + } else { + assert(hop > 0); + strcpy(addr, remailer[thischain[hop - 1]].addr); + }; + buf_append(encrypted, addr, 80); + } else { + if (numpackets == 1) + buf_appendc(encrypted, 1); + else { + buf_appendc(encrypted, 2); + buf_appendc(encrypted, (byte) packetnum); + buf_appendc(encrypted, (byte) numpackets); + } + buf_cat(encrypted, mid); + buf_cat(encrypted, iv); /* body encryption IV */ + } + + /* timestamp */ + buf_appends(encrypted, "0000"); + buf_appendc(encrypted, '\0'); /* timestamp magic */ + timestamp = time(NULL) / SECONDSPERDAY - rnd_number(4); + buf_appendi_lo(encrypted, timestamp); + + /* message digest for this header */ + digest_md5(encrypted, temp); + buf_cat(encrypted, temp); + buf_pad(encrypted, 328); + + /* encrypt message body */ + buf_crypt(body, key, iv, ENCRYPT); + + if (hop > 0 || redirect_to != NULL) { + /* encrypt the other header charts */ + buf_clear(other); + for (i = 0; i < 19; i++) { + buf_clear(iv); + buf_clear(temp); + buf_append(iv, ivarray->data + 8 * i, 8); + buf_append(temp, header->data + 512 * i, 512); + buf_crypt(temp, key, iv, ENCRYPT); + buf_cat(other, temp); + } + } else + buf_setrnd(other, 19 * 512); /* fill with random data */ + + /* create session key and IV to encrypt the header ... */ + buf_setrnd(key, 24); + buf_setrnd(iv, 8); + buf_crypt(encrypted, key, iv, ENCRYPT); + pubkey = buf_new(); + err = db_getpubkey(remailer[thischain[hop]].keyid, pubkey); + if (err == -1) + goto end; + err = pk_encrypt(key, pubkey); /* ... and encrypt the + session key */ + buf_free(pubkey); + if (err == -1 || key->length != 128) { + clienterr(feedback, "Encryption failed!"); + err = -1; + goto end; + } + /* now build the new header */ + buf_clear(header); + buf_append(header, remailer[thischain[hop]].keyid, 16); + buf_appendc(header, 128); + buf_cat(header, key); + buf_cat(header, iv); + buf_cat(header, encrypted); + buf_pad(header, 512); + buf_cat(header, other); + break; + default: + err = -1; + goto end; + } + } + + /* build the message */ + buf_sets(out, remailer[thischain[chainlen - 1]].addr); + buf_nl(out); + buf_cat(out, header); + buf_cat(out, body); + assert(header->length == 10240 && body->length == 10240); + mix_pool(out, INTERMEDIATE, -1); + + if (feedback) { + for (hop = chainlen - 1; hop >= 0; hop--) { + buf_appends(feedback, remailer[thischain[hop]].name); + if (hop > 0) + buf_appendc(feedback, ','); + } + buf_nl(feedback); + } + } +end: + buf_free(pid); + buf_free(body); + buf_free(out); + buf_free(header); + buf_free(temp); + buf_free(other); + buf_free(key); + buf_free(encrypted); + buf_free(iv); + buf_free(ivarray); + return (err); +} + +int redirect_message(BUFFER *sendmsg, char *chainstr, int numcopies, BUFFER *feedback) +{ + BUFFER *field; + BUFFER *content; + BUFFER *line; + char recipient[80] = ""; + int num = 0; + int err = 0; + int c; + int hop; + + REMAILER remailer[MAXREM]; + int chain[20]; + int thischain[20]; + int chainlen; + int badchains[MAXREM][MAXREM]; + int maxrem; + int tempchain[20]; + int tempchainlen; + int israndom; + + field = buf_new(); + content = buf_new(); + line = buf_new(); + + if (numcopies == 0) + numcopies = NUMCOPIES; + if (numcopies > 10) + numcopies = 10; + + /* Find the recipient */ + while (buf_getheader(sendmsg, field, content) == 0) + if (bufieq(field, "to")) { + strncpy(recipient, content->data, sizeof(recipient)); + num++; + }; + if (num != 1) { + clienterr(feedback, "Did not find exactly one To: address!"); + err = -1; + goto end; + }; + + /* Dearmor the message */ + err = mix_dearmor(sendmsg, sendmsg); + if (err == -1) + goto end; + assert (sendmsg->length == 20480); + + /* Check the chain */ + maxrem = mix2_rlist(remailer, badchains); + if (maxrem < 1) { + clienterr(feedback, "No remailer list!"); + err = -1; + goto end; + } + chainlen = chain_select(chain, chainstr, maxrem, remailer, 0, line); + if (chainlen < 1) { + if (line->length) + clienterr(feedback, line->data); + else + clienterr(feedback, "Invalid remailer chain!"); + err = -1; + goto end; + } else if (chainlen >= 20) { + clienterr(feedback, "A chainlength of 20 will certainly destroy the message!"); + err = -1; + goto end; + }; + + + for (c = 0; c < numcopies; c++) { + /* if our recipient is a remailer we want to make sure we're not using a known broken chain. + * therefore we need to pick the final remailer with care */ + for (hop = 0; hop < chainlen; hop++) + thischain[hop] = chain[hop]; + if (thischain[0] == 0) { + /* Find out, if recipient is a remailer */ + tempchainlen = chain_select(tempchain, recipient, maxrem, remailer, 0, line); + if (tempchainlen < 1 && line->length == 0) { + /* recipient is apparently not a remailer we know about */ + ; + } else { + /* Build a new chain, based on the one we already selected but + * with the recipient as the final hop. + * This is so that chain_rand properly selects nodes based on + * broken chains and DISTANCE */ + assert(chainlen < 20); + for (hop = 0; hop < chainlen; hop++) + thischain[hop+1] = thischain[hop]; + thischain[0] = tempchain[0]; + + israndom = chain_rand(remailer, badchains, maxrem, thischain, chainlen + 1, 0, 0); + if (israndom == -1) { + err = -1; + clienterr(feedback, "No reliable remailers!"); + goto end; + } + + /* Remove the added recipient hop */ + for (hop = 0; hop < chainlen; hop++) + thischain[hop] = thischain[hop + 1]; + }; + }; + + /* queue the packet */ + if (send_packet(1, sendmsg, thischain, chainlen, + -1, -1, NULL, + remailer, badchains, maxrem, recipient, 0, feedback) == -1) + err = -1; + }; + +end: + buf_free(field); + buf_free(content); + buf_free(line); + return (err); +} + +int mix2_encrypt(int type, BUFFER *message, char *chainstr, int numcopies, + int ignore_constraints_if_necessary, + BUFFER *feedback) +{ + /* returns 0 on success, -1 on error. feedback contains the selected + remailer chain or an error message + + ignore_constraints_if_necessary .. to be used when randhopping messages. + if a chain can not be constructed otherwhise, + maxlat, minlat, and minrel are ignored. + */ + + REMAILER remailer[MAXREM]; + int badchains[MAXREM][MAXREM]; + int maxrem; + BUFFER *line, *field, *content, *header, *msgdest, *msgheader, *body, + *temp, *mid; + byte numdest = 0, numhdr = 0; + char hdrline[LINELEN]; + BUFFER *packet; + int chain[20]; + int chainlen; + int i; + int err = 0; + + mix_init(NULL); + packet = buf_new(); + line = buf_new(); + field = buf_new(); + content = buf_new(); + msgheader = buf_new(); + msgdest = buf_new(); + body = buf_new(); + temp = buf_new(); + mid = buf_new(); + header = buf_new(); + if (feedback) + buf_reset(feedback); + + if (numcopies == 0) + numcopies = NUMCOPIES; + if (numcopies > 10) + numcopies = 10; + + maxrem = mix2_rlist(remailer, badchains); + if (maxrem < 1) { + clienterr(feedback, "No remailer list!"); + err = -1; + goto end; + } + chainlen = chain_select(chain, chainstr, maxrem, remailer, 0, line); + if (chainlen < 1) { + if (line->length) + clienterr(feedback, line->data); + else + clienterr(feedback, "Invalid remailer chain!"); + err = -1; + goto end; + } + if (chain[0] == 0) + chain[0] = chain_randfinal(type, remailer, badchains, maxrem, 0, chain, chainlen, ignore_constraints_if_necessary); + + if (chain[0] == -1) { + clienterr(feedback, "No reliable remailers!"); + err = -1; + goto end; + } + switch (remailer[chain[0]].version) { + case 2: + if (type == MSG_NULL) { + memset(hdrline, 0, 80); + strcpy(hdrline, "null:"); + buf_append(msgdest, hdrline, 80); + numdest++; + } else + while (buf_getheader(message, field, content) == 0) { + if (bufieq(field, "to")) { + memset(hdrline, 0, 80); + strncpy(hdrline, content->data, 80); + buf_append(msgdest, hdrline, 80); + numdest++; + } else if (type == MSG_POST && bufieq(field, "newsgroups")) { + memset(hdrline, 0, 80); + strcpy(hdrline, "post: "); + strcatn(hdrline, content->data, 80); + buf_append(msgdest, hdrline, 80); + numdest++; + } else { + buf_clear(header); + buf_appendheader(header, field, content); + hdr_encode(header, 80); + while (buf_getline(header, line) == 0) { + /* paste in encoded header entry */ + memset(hdrline, 0, 80); + strncpy(hdrline, line->data, 80); + buf_append(msgheader, hdrline, 80); + numhdr++; + } + } + } + buf_appendc(body, numdest); + buf_cat(body, msgdest); + buf_appendc(body, numhdr); + buf_cat(body, msgheader); + + if (type != MSG_NULL) { + buf_rest(temp, message); + if (temp->length > 10236 && remailer[chain[0]].flags.compress) + buf_compress(temp); + buf_cat(body, temp); + buf_reset(temp); + } + buf_setrnd(mid, 16); /* message ID */ + for (i = 0; i <= body->length / 10236; i++) { + long length; + + length = body->length - i * 10236; + if (length > 10236) + length = 10236; + buf_clear(packet); + buf_appendl_lo(packet, length); + buf_append(packet, body->data + i * 10236, length); + buf_pad(packet, 10240); + if (send_packet(numcopies, packet, chain, chainlen, + i + 1, body->length / 10236 + 1, + mid, remailer, badchains, maxrem, NULL, ignore_constraints_if_necessary, feedback) == -1) + err = -1; + } + break; + case 3: + NOT_IMPLEMENTED; + break; + default: + fprintf(stderr, "%d\n", chain[0]); + clienterr(feedback, "Unknown remailer version!"); + err = -1; + } + +end: + buf_free(packet); + buf_free(line); + buf_free(field); + buf_free(content); + buf_free(header); + buf_free(msgheader); + buf_free(msgdest); + buf_free(body); + buf_free(temp); + buf_free(mid); + return (err); +} diff --git a/Src/compress.c b/Src/compress.c @@ -0,0 +1,210 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Buffer compression (interface to zlib) + $Id: compress.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <stdio.h> +#include <assert.h> + +static byte gz_magic[2] = +{0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 +#define HEAD_CRC 0x02 +#define EXTRA_FIELD 0x04 +#define ORIG_NAME 0x08 +#define COMMENT 0x10 +#define RESERVED 0xE0 +#define Z_DEFLATED 8 + +#ifdef USE_ZLIB +#include "zlib.h" + +int buf_unzip(BUFFER *in, int type) +{ + BUFFER *out; + z_stream s; + long outstart; + int err; + int ret = 0; + + out = buf_new(); + + s.zalloc = (alloc_func) 0; + s.zfree = (free_func) 0; + s.opaque = (voidpf) 0; + + s.next_in = in->data + in->ptr; + s.avail_in = in->length + 1 - in->ptr; /* terminating 0 byte as "dummy" */ + s.next_out = NULL; + + if (type == 1) + err = inflateInit(&s); /* zlib */ + else + err = inflateInit2(&s, -MAX_WBITS); + if (err != Z_OK) { + ret = -1; + goto end; + } + outstart = 0; + buf_append(out, NULL, in->length * 15 / 10); + + for (;;) { + s.next_out = out->data + s.total_out + outstart; + s.avail_out = out->length - outstart - s.total_out; + err = inflate(&s, Z_PARTIAL_FLUSH); + out->length -= s.avail_out; + if (err != Z_OK) + break; + buf_append(out, NULL, BUFSIZE); + } + if (err != Z_STREAM_END) + errlog(WARNING, "Decompression error %d\n", err); + + err = inflateEnd(&s); + if (err != Z_OK) + ret = -1; +end: + if (ret != 0) + switch (err) { + case Z_STREAM_ERROR: + errlog(ERRORMSG, "Decompression error Z_STREAM_ERROR.\n", err); + break; + case Z_MEM_ERROR: + errlog(ERRORMSG, "Decompression error Z_MEM_ERROR.\n", err); + break; + case Z_BUF_ERROR: + errlog(ERRORMSG, "Decompression error Z_BUF_ERROR.\n", err); + break; + case Z_VERSION_ERROR: + errlog(ERRORMSG, "Decompression error Z_VERSION_ERROR.\n", err); + break; + default: + errlog(ERRORMSG, "Decompression error %d.\n", err); + } + buf_move(in, out); + buf_free(out); + return (ret); +} + +int buf_zip(BUFFER *out, BUFFER *in, int bits) +{ + z_stream s; + long outstart; + int err = -1; + + assert(in != out); + + s.zalloc = (alloc_func) 0; + s.zfree = (free_func) 0; + s.opaque = (voidpf) 0; + s.next_in = NULL; + + if (bits == 0) + bits = MAX_WBITS; + + if (deflateInit2(&s, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -bits, 8, 0) != Z_OK) + goto end; + + outstart = out->length; + /* 12 is overhead, 1.01 is maximum expansion, and 1 is there to force a round-up */ + buf_append(out, NULL, (int)13+in->length*1.01); /* fit it in one chunk */ + + s.next_in = in->data; + s.avail_in = in->length; + + for (;;) { + s.next_out = out->data + s.total_out + outstart; + s.avail_out = out->length - outstart - s.total_out; + err = deflate(&s, Z_FINISH); + out->length -= s.avail_out; + if (err != Z_OK) + break; + errlog(ERRORMSG, "Compressed data did not fit in one chunk.\n"); + buf_append(out, NULL, BUFSIZE); + } + if (deflateEnd(&s) != Z_OK || err != Z_STREAM_END) + err = -1; + else + err = 0; +end: + if (err != 0) + errlog(ERRORMSG, "Compression error.\n"); + return (err); +} + +#else /* end of USE_ZLIB */ +int buf_zip(BUFFER *out, BUFFER *in, int bits) +{ + return (-1); +} + +int buf_unzip(BUFFER *b, int type) +{ + errlog(ERRORMSG, "Can't uncompress: no zlib\n"); + return (-1); +} +#endif /* else not USE_ZLIB */ + +int compressed(BUFFER *b) +{ + return (b->length >= 10 && b->data[0] == gz_magic[0] && + b->data[1] == gz_magic[1]); +} + +int buf_uncompress(BUFFER *in) +{ + int type; + int err = -1; + unsigned int len; + + if (!compressed(in)) + return (0); + type = in->data[3]; + if (in->data[2] != Z_DEFLATED || (type & RESERVED) == 0) { + in->ptr = 10; + if ((type & EXTRA_FIELD) != 0) { + len = buf_geti(in); + in->ptr += len; + } + if ((type & ORIG_NAME) != 0) + while (buf_getc(in) > 0) ; + if ((type & COMMENT) != 0) + while (buf_getc(in) > 0) ; + if ((type & HEAD_CRC) != 0) + buf_geti(in); + err = buf_unzip(in, 0); + } + return (err); +} + +int buf_compress(BUFFER *in) +{ + BUFFER *out; + int err; + + if (compressed(in)) + return (0); + + out = buf_new(); + buf_appendc(out, gz_magic[0]); + buf_appendc(out, gz_magic[1]); + buf_appendc(out, Z_DEFLATED); + buf_appendc(out, 0); /* flags */ + buf_appendl(out, 0); /* time */ + buf_appendc(out, 0); /* xflags */ + buf_appendc(out, 3); /* Unix */ + err = buf_zip(out, in, 0); + if (err == 0) + buf_move(in, out); + buf_free(out); + return (err); +} diff --git a/Src/config.h b/Src/config.h @@ -0,0 +1,403 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2008 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Configuration + $Id: config.h 973 2008-03-03 16:55:38Z rabbi $ */ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "version.h" +#ifndef WIN32 +#include "sys/param.h" +#endif /* WIN32 */ + +/* Disclaimer to be inserted in all anonymous messages: */ +#define DISCLAIMER \ + "Comments: This message did not originate from the Sender address above.\n" \ + "\tIt was remailed automatically by anonymizing remailer software.\n" \ + "\tPlease report problems or inappropriate use to the\n" \ + "\tremailer administrator at <%s>.\n" /* (%s is the complaints address) */ + +/* Additional disclaimer to be inserted in the body of messages with + * user-supplied From lines, e.g. + * "NOTE: The above From: line has not been authenticated!\n\n" */ +#define FROMDISCLAIMER "" + +/* Additional disclaimer to be inserted at the bottom of the body of all + * messages */ +#define MSGFOOTER "" + +/* Comment to be inserted when a binary attachment is filtered out: */ +#define BINDISCLAIMER \ + "[...]" + +/* Character set for MIME-encoded mail header lines */ +#define MIMECHARSET "iso-8859-1" +#if 1 +#define DEFLTENTITY "" +#else +#define DEFLTENTITY "text/plain; charset=" MIMECHARSET +#endif + +#ifdef WIN32 +/* Use the PCRE regular expression library for destination blocking? */ +#define USE_PCRE +/* Use zlib for compression? */ +#define USE_ZLIB +/* Use ncurses? */ +#define USE_NCURSES +/* Use the WIN GUI? */ +#define USE_WINGUI +/* Use sockets to deliver mail */ +#define USE_SOCK +/* Compile in Win32 service support */ +#define WIN32SERVICE +#endif /* WIN32 */ + +/** System dependencies **********************************************/ +/* Macros: UNIX for Unix-style systems + POSIX for systems with POSIX header files (including DJGPP) + MSDOS for 32 bit DOS + WIN32 for Windows 95/NT */ + +#if defined(_WIN32) && !defined(WIN32) +#define WIN32 +#endif + +#if defined(__RSXNT__) && !defined(WIN32) +#define WIN32 +#endif + +#if !defined(UNIX) && !defined(WIN32) && !defined(MSDOS) +#define UNIX +#endif + +#if defined(UNIX) && !defined(POSIX) +#define POSIX +#endif + +#ifdef UNIX +#define DEV_URANDOM "/dev/urandom" +#ifdef __OpenBSD__ +#define DEV_RANDOM "/dev/arandom" +#else +#define DEV_RANDOM "/dev/random" +#endif +#endif + +#ifdef POSIX +# define HAVE_TERMIOS +#endif /* POSIX */ + +#ifdef MSDOS +#define SHORTNAMES +#ifndef WIN32 +#define HAVE_GETKEY +#undef USE_SOCK +#endif +#endif + +#if defined(USE_WINGUI) && !defined(WIN32) +#error "The GUI requires Win32!" +#endif + +#if defined(WIN32) && !defined(_USRDLL) +#define DLLIMPORT __declspec(dllimport) +#else +#define DLLIMPORT +#endif + +/* This block includes the config.h created by autoconf/configure. + * Eventually this old config.h stuff should be merged with the autoconf + * stuff perhaps. */ +#ifdef HAVE_CONFIG_H +# include "../config.h" +#else /* End of HAVE_CONFIG_H */ + +/* Setup for stuff that happens when autoconf isn't run. This should be + * removed once we finally nuke that damn Install script. */ + +/** Libraries and library functions **********************************/ + +/* Use the OpenSSL crypto library (required) */ +#define USE_OPENSSL +/* Use IDEA algorithm? (See file idea.txt) */ +/* #define USE_IDEA */ +/* Use AES algorithm? - should be handled by Install script setting compiler option -DUSE_AES */ +/* #define USE_AES */ +/* Support the OpenPGP message format? */ +#define USE_PGP + +#ifdef UNIX +# define HAVE_UNAME +# define HAVE_GECOS +#endif + +#if defined(POSIX) || defined(USE_SOCK) +# define HAVE_GETHOSTNAME +#endif + +#ifdef POSIX +/* not a POSIX function, but avaiable on virtually all Unix systems */ +# define HAVE_GETTIMEOFDAY +#endif + +#ifdef linux +# define HAVE_GETDOMAINNAME +#endif + +#ifdef WIN32 +# ifdef _MSC_VER +#pragma warning(disable: 4018) /* signed/unsigned mismatch */ +#pragma warning(disable: 4761) /* integral size mismatch */ +# endif +#endif + + +#endif /* End of not HAVE_CONFIG_H */ + +/** Constants *********************************************************/ + +/* Give up if a file is larger than BUFFER_MAX bytes: */ +/* #define BUFFER_MAX 64*1024*1024 */ + +#ifdef MAXPATHLEN +#define PATHMAX MAXPATHLEN +#else /* MAXPATHLEN */ +#ifdef _MSC +#define PATHMAX MAX_PATH +#else /* _MSC */ +#define PATHMAX 512 +#endif /* not _MSC */ +#endif /* not MAXPATHLEN */ +#define LINELEN 128 +#define BUFSIZE 4096 + +/** if it is a systemwide installation defined GLOBALMIXCONF **********/ +/* #define GLOBALMIXCONF "/etc/mix.cfg" */ + +/* The path to append to a user's homedirectory for his local Mix dir */ +#ifndef HOMEMIXDIR +#define HOMEMIXDIR "Mix" +#endif + +/** file names ********************************************************/ + +#ifdef WIN32 +#define DEFAULT_MIXCONF "mix.cfg" /* change to mix.ini eventually */ +#else +#define DEFAULT_MIXCONF "mix.cfg" /* mixmaster configuration file */ +#endif +#define DEFAULT_DISCLAIMFILE "disclaim.txt" +#define DEFAULT_FROMDSCLFILE "fromdscl.txt" +#define DEFAULT_MSGFOOTERFILE "footer.txt" +#ifdef WIN32 +#define DEFAULT_POP3CONF "pop3.cfg" /* change to pop3.ini eventually */ +#else +#define DEFAULT_POP3CONF "pop3.cfg" +#endif +#define DEFAULT_HELPFILE "help.txt" +#define DEFAULT_REQUESTDIR "requests" +#define DEFAULT_ABUSEFILE "abuse.txt" +#define DEFAULT_REPLYFILE "reply.txt" +#define DEFAULT_USAGEFILE "usage.txt" +#define DEFAULT_USAGELOG "usage.log" +#define DEFAULT_BLOCKFILE "blocked.txt" +#define DEFAULT_ADMKEYFILE "adminkey.txt" +#define DEFAULT_KEYFILE "key.txt" +#define DEFAULT_PGPKEY "pgpkey.txt" +#define DEFAULT_DSAPARAMS "dsaparam.mix" +#define DEFAULT_DHPARAMS "dhparam.mix" +#define DEFAULT_MIXRAND "mixrand.bin" +#define DEFAULT_SECRING "secring.mix" +#define DEFAULT_PUBRING "pubring.mix" +#define DEFAULT_IDLOG "id.log" +#define DEFAULT_STATS "stats.log" +#define DEFAULT_PGPMAXCOUNT "pgpmaxcount.log" +/* To enable multiple dest.blk files, edit the following line. */ +/* Filenames must be seperated by one space. */ +#define DEFAULT_DESTBLOCK "dest.blk rab.blk" +#define DEFAULT_DESTALLOW "dest.alw" +#define DEFAULT_DESTALLOW2 "dest.alw.nonpublished" +#define DEFAULT_SOURCEBLOCK "source.blk" +#define DEFAULT_HDRFILTER "header.blk" +#define DEFAULT_REGULAR "time.log" +#define DEFAULT_POOL "pool" /* remailer pool subdirectory */ +#define DEFAULT_TYPE1LIST "rlist.txt" +#define DEFAULT_TYPE2REL "mlist.txt" +#define DEFAULT_PIDFILE "mixmaster.pid" +#define DEFAULT_STATSSRC "stats-src.txt" + +#define DEFAULT_PGPREMPUBRING "pubring.pgp" +#define DEFAULT_PGPREMPUBASC "pubring.asc" +#define DEFAULT_PGPREMSECRING "secring.pgp" +#define DEFAULT_NYMSECRING "nymsec.pgp" +#define DEFAULT_NYMDB "secrets.mix" +#define DEFAULT_STAREX "starex.txt" +#define DEFAULT_ALLPINGERSURL "http://www.noreply.org/allpingers/allpingers.txt" +#define DEFAULT_ALLPINGERSFILE "allpingers.txt" +#define DEFAULT_WGET "wget" + +DLLIMPORT extern char MIXCONF[]; +extern char DISCLAIMFILE[]; +extern char FROMDSCLFILE[]; +extern char MSGFOOTERFILE[]; +extern char POP3CONF[]; +extern char HELPFILE[]; +extern char REQUESTDIR[]; +extern char ABUSEFILE[]; +extern char REPLYFILE[]; +extern char USAGEFILE[]; +extern char USAGELOG[]; +extern char BLOCKFILE[]; +extern char ADMKEYFILE[]; +extern char KEYFILE[]; +extern char PGPKEY[]; +extern char DSAPARAMS[]; +extern char DHPARAMS[]; +extern char MIXRAND[]; +extern char SECRING[]; +extern char PUBRING[]; +extern char IDLOG[]; +extern char STATS[]; +extern char PGPMAXCOUNT[]; +extern char DESTBLOCK[]; +extern char DESTALLOW[]; +extern char DESTALLOW2[]; +extern char SOURCEBLOCK[]; +extern char HDRFILTER[]; +extern char REGULAR[]; +extern char POOL[]; +extern char TYPE1LIST[]; +extern char TYPE2REL[]; +extern char PIDFILE[]; +extern char STAREX[]; + +extern char PGPREMPUBRING[]; +extern char PGPREMPUBASC[]; +extern char PGPREMSECRING[]; +DLLIMPORT extern char NYMSECRING[]; +extern char NYMDB[]; + +/* string constants */ +#define remailer_type "Remailer-Type: Mixmaster " +#define mixmaster_protocol "2" +#define begin_remailer "-----BEGIN REMAILER MESSAGE-----" +#define end_remailer "-----END REMAILER MESSAGE-----" +#define begin_key "-----Begin Mix Key-----" +#define end_key "-----End Mix Key-----" +#define begin_pgp "-----BEGIN PGP " +#define end_pgp "-----END PGP " +#define begin_pgpmsg "-----BEGIN PGP MESSAGE-----" +#define end_pgpmsg "-----END PGP MESSAGE-----" +#define begin_pgpkey "-----BEGIN PGP PUBLIC KEY BLOCK-----" +#define end_pgpkey "-----END PGP PUBLIC KEY BLOCK-----" +#define begin_pgpseckey "-----BEGIN PGP PRIVATE KEY BLOCK-----" +#define end_pgpseckey "-----END PGP PRIVATE KEY BLOCK-----" +#define begin_pgpsigned "-----BEGIN PGP SIGNED MESSAGE-----" +#define begin_pgpsig "-----BEGIN PGP SIGNATURE-----" +#define end_pgpsig "-----END PGP SIGNATURE-----" +#define info_beginpgp "=====BEGIN PGP MESSAGE=====" +#define info_endpgp "=====END PGP MESSAGE=====" +#define info_pgpsig "=====Sig: " + + +/*********************************************************************** + * The following variables are read from mix.cfg, with default values + * defined in mix.c */ + +int REMAIL; +int MIX; +int PGP; +int UNENCRYPTED; +int REMIX; +int REPGP; +extern char MIXDIR[]; +extern char POOLDIR[]; +extern char EXTFLAGS[]; +extern char SENDMAIL[]; +extern char SENDANONMAIL[]; +extern char PRECEDENCE[]; +extern char SMTPRELAY[]; +extern char SMTPUSERNAME[]; +extern char SMTPPASSWORD[]; +extern char NEWS[]; +extern char MAILtoNEWS[]; +extern char ORGANIZATION[]; +extern char MID[]; +extern char TYPE1[]; +extern char ERRLOG[]; +extern char NAME[]; +extern char ADDRESS[]; +extern char REMAILERADDR[]; +extern char ANONADDR[]; +extern char REMAILERNAME[]; +extern char ANONNAME[]; +extern char COMPLAINTS[]; +extern int AUTOREPLY; +extern char HELONAME[]; +extern char ENVFROM[]; +extern char SHORTNAME[]; +extern int POOLSIZE; +DLLIMPORT extern int RATE; +extern int INDUMMYP; +extern int OUTDUMMYP; +extern int MIDDLEMAN; +extern int AUTOBLOCK; +extern int STATSDETAILS; +extern char FORWARDTO[]; +extern int SIZELIMIT; +extern int INFLATEMAX; +extern int MAXRANDHOPS; +extern int BINFILTER; +extern int LISTSUPPORTED; +extern long PACKETEXP; +extern long IDEXP; +DLLIMPORT extern int VERBOSE; +DLLIMPORT extern long SENDPOOLTIME; +extern long MAILINTIME; +extern long KEYLIFETIME; +extern long KEYOVERLAPPERIOD; +extern long KEYGRACEPERIOD; +extern int NUMCOPIES; +extern char CHAIN[]; +extern int DISTANCE; +extern int MINREL; +extern int RELFINAL; +extern long MAXLAT; +extern long MINLAT; +DLLIMPORT extern char PGPPUBRING[]; +DLLIMPORT extern char PGPSECRING[]; +DLLIMPORT extern char PASSPHRASE[]; +extern long POP3TIME; +extern int POP3DEL; +extern int POP3SIZELIMIT; +extern char MAILBOX[]; +extern char MAILIN[]; +extern char MAILABUSE[]; +extern char MAILBLOCK[]; +extern char MAILUSAGE[]; +extern char MAILANON[]; +extern char MAILERROR[]; +extern char MAILBOUNCE[]; +DLLIMPORT extern int CLIENTAUTOFLUSH; +extern int MAXRECIPIENTS; +extern long TIMESKEW_FORWARD; +extern long TIMESKEW_BACK; +extern int TEMP_FAIL; +extern char ALLPINGERSURL[]; +extern char ALLPINGERSFILE[]; + +extern char WGET[]; +extern char STATSSRC[]; +extern int STATSAUTOUPDATE; +extern long STATSINTERVAL; + +DLLIMPORT extern char ENTEREDPASSPHRASE[LINELEN]; + +#endif diff --git a/Src/crypto.c b/Src/crypto.c @@ -0,0 +1,492 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Interface to cryptographic library + $Id: crypto.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include "crypto.h" +#include <assert.h> +#include <string.h> +#include <time.h> + +#ifdef USE_OPENSSL +int digestmem_md5(byte *b, int n, BUFFER *md) +{ + byte m[MD5_DIGEST_LENGTH]; + + MD5(b, n, m); + buf_reset(md); + buf_append(md, m, MD5_DIGEST_LENGTH); + return (0); +} + +int digest_md5(BUFFER *b, BUFFER *md) +{ + return (digestmem_md5(b->data, b->length, md)); +} + +int isdigest_md5(BUFFER *b, BUFFER *md) +{ + int ret; + BUFFER *newmd; + + newmd = buf_new(); + digest_md5(b, newmd); + ret = buf_eq(md, newmd); + buf_free(newmd); + return (ret); +} + +static int digestmem_sha1(byte *b, int n, BUFFER *md) +{ + byte m[SHA_DIGEST_LENGTH]; + + SHA1(b, n, m); + buf_reset(md); + buf_append(md, m, SHA_DIGEST_LENGTH); + return (0); +} + +int digest_sha1(BUFFER *b, BUFFER *md) +{ + return (digestmem_sha1(b->data, b->length, md)); +} + +static int digestmem_rmd160(byte *b, int n, BUFFER *md) +{ + byte m[RIPEMD160_DIGEST_LENGTH]; + + RIPEMD160(b, n, m); + buf_reset(md); + buf_append(md, m, RIPEMD160_DIGEST_LENGTH); + return (0); +} + +int digest_rmd160(BUFFER *b, BUFFER *md) +{ + return (digestmem_rmd160(b->data, b->length, md)); +} + +#define MAX_RSA_MODULUS_LEN 128 + +static int read_seckey(BUFFER *buf, SECKEY *key, const byte id[]) +{ + BUFFER *md; + int bits; + int len, plen; + byte *ptr; + int err = 0; + + md = buf_new(); + bits = buf->data[0] + 256 * buf->data[1]; + len = (bits + 7) / 8; + plen = (len + 1) / 2; + + /* due to encryption, buffer size is multiple of 8 */ + if (3 * len + 5 * plen + 8 < buf->length || 3 * len + 5 * plen > buf->length) + return (-1); + + ptr = buf->data + 2; + + key->n = BN_bin2bn(ptr, len, NULL); + buf_append(md, ptr, len); + ptr += len; + + key->e = BN_bin2bn(ptr, len, NULL); + buf_append(md, ptr, len); + ptr += len; + + key->d = BN_bin2bn(ptr, len, NULL); + ptr += len; + + key->p = BN_bin2bn(ptr, plen, NULL); + ptr += plen; + + key->q = BN_bin2bn(ptr, plen, NULL); + ptr += plen; + + key->dmp1 = BN_bin2bn(ptr, plen, NULL); + ptr += plen; + + key->dmq1 = BN_bin2bn(ptr, plen, NULL); + ptr += plen; + + key->iqmp = BN_bin2bn(ptr, plen, NULL); + ptr += plen; + + digest_md5(md, md); + if (id) + err = (memcmp(id, md->data, 16) == 0) ? 0 : -1; + buf_free(md); + return (err); +} + +static int read_pubkey(BUFFER *buf, PUBKEY *key, const byte id[]) +{ + BUFFER *md; + int bits; + int len; + byte *ptr; + int err = 0; + + md = buf_new(); + bits = buf->data[0] + 256 * buf->data[1]; + len = (bits + 7) / 8; + + if (2 * len + 2 != buf->length) + return (-1); + + ptr = buf->data + 2; + + key->n = BN_bin2bn(ptr, len, NULL); + buf_append(md, ptr, len); + ptr += len; + + key->e = BN_bin2bn(ptr, len, NULL); + buf_append(md, ptr, len); + ptr += len; + + digest_md5(md, md); + if (id) + err = (memcmp(id, md->data, 16) == 0) ? 0 : -1; + buf_free(md); + return (err); +} + +static int write_seckey(BUFFER *sk, SECKEY *key, byte keyid[]) +{ + byte l[128]; + int n; + BUFFER *b, *temp; + + b = buf_new(); + temp = buf_new(); + + n = BN_bn2bin(key->n, l); + assert(n <= 128); + if (n < 128) + buf_appendzero(b, 128 - n); + buf_append(b, l, n); + + n = BN_bn2bin(key->e, l); + assert(n <= 128); + if (n < 128) + buf_appendzero(b, 128 - n); + buf_append(b, l, n); + + digest_md5(b, temp); + memcpy(keyid, temp->data, 16); + + buf_appendc(sk, 0); + buf_appendc(sk, 4); + buf_cat(sk, b); + + n = BN_bn2bin(key->d, l); + assert(n <= 128); + if (n < 128) + buf_appendzero(sk, 128 - n); + buf_append(sk, l, n); + + n = BN_bn2bin(key->p, l); + assert(n <= 64); + if (n < 64) + buf_appendzero(sk, 64 - n); + buf_append(sk, l, n); + + n = BN_bn2bin(key->q, l); + assert(n <= 64); + if (n < 64) + buf_appendzero(sk, 64 - n); + buf_append(sk, l, n); + + n = BN_bn2bin(key->dmp1, l); + assert(n <= 64); + if (n < 64) + buf_appendzero(sk, 64 - n); + buf_append(sk, l, n); + + n = BN_bn2bin(key->dmq1, l); + assert(n <= 64); + if (n < 64) + buf_appendzero(sk, 64 - n); + buf_append(sk, l, n); + + n = BN_bn2bin(key->iqmp, l); + assert(n <= 64); + if (n < 64) + buf_appendzero(sk, 64 - n); + buf_append(sk, l, n); + + buf_pad(sk, 712); /* encrypt needs a block size multiple of 8 */ + + buf_free(temp); + buf_free(b); + return (0); +} + +static int write_pubkey(BUFFER *pk, PUBKEY *key, byte keyid[]) +{ + byte l[128]; + int n; + + buf_appendc(pk, 0); + buf_appendc(pk, 4); + n = BN_bn2bin(key->n, l); + assert(n <= 128); + if (n < 128) + buf_appendzero(pk, 128 - n); + buf_append(pk, l, n); + n = BN_bn2bin(key->e, l); + assert(n <= 128); + if (n < 128) + buf_appendzero(pk, 128 - n); + buf_append(pk, l, n); + return (0); +} + +int seckeytopub(BUFFER *pub, BUFFER *sec, byte keyid[]) +{ + RSA *k; + int err = 0; + + k = RSA_new(); + err = read_seckey(sec, k, keyid); + if (err == 0) + err = write_pubkey(pub, k, keyid); + RSA_free(k); + return (err); +} + +int check_pubkey(BUFFER *buf, const byte id[]) +{ + RSA *tmp; + int ret; + + tmp = RSA_new(); + ret = read_pubkey(buf, tmp, id); + RSA_free(tmp); + return (ret); +} + +int check_seckey(BUFFER *buf, const byte id[]) +{ + RSA *tmp; + int ret; + + tmp = RSA_new(); + ret = read_seckey(buf, tmp, id); + RSA_free(tmp); + return (ret); +} + +int v2createkey(void) +{ + RSA *k; + BUFFER *b, *ek, *iv; + int err; + FILE *f; + byte keyid[16]; + char line[33]; + + b = buf_new(); + ek = buf_new(); + iv = buf_new(); + + errlog(NOTICE, "Generating RSA key.\n"); + k = RSA_generate_key(1024, 65537, NULL, NULL); + err = write_seckey(b, k, keyid); + RSA_free(k); + if (err == 0) { + f = mix_openfile(SECRING, "a"); + if (f != NULL) { + time_t now = time(NULL); + struct tm *gt; + gt = gmtime(&now); + strftime(line, LINELEN, "%Y-%m-%d", gt); + fprintf(f, "%s\nCreated: %s\n", begin_key, line); + if (KEYLIFETIME) { + now += KEYLIFETIME; + gt = gmtime(&now); + strftime(line, LINELEN, "%Y-%m-%d", gt); + fprintf(f, "Expires: %s\n", line); + } + id_encode(keyid, line); + buf_appends(ek, PASSPHRASE); + digest_md5(ek, ek); + buf_setrnd(iv, 8); + buf_crypt(b, ek, iv, ENCRYPT); + encode(b, 40); + encode(iv, 0); + fprintf(f, "%s\n0\n%s\n", line, iv->data); + buf_write(b, f); + fprintf(f, "%s\n\n", end_key); + fclose(f); + } else + err = -1; + } + if (err != 0) + errlog(ERRORMSG, "Key generation failed.\n"); + + buf_free(b); + buf_free(ek); + buf_free(iv); + return (err); +} + +int pk_decrypt(BUFFER *in, BUFFER *keybuf) +{ + int err = 0; + BUFFER *out; + RSA *key; + + out = buf_new(); + key = RSA_new(); + read_seckey(keybuf, key, NULL); + + buf_prepare(out, in->length); + out->length = RSA_private_decrypt(in->length, in->data, out->data, key, + RSA_PKCS1_PADDING); + if (out->length == -1) + err = -1, out->length = 0; + + RSA_free(key); + buf_move(in, out); + buf_free(out); + return (err); +} + +int pk_encrypt(BUFFER *in, BUFFER *keybuf) +{ + BUFFER *out; + RSA *key; + int err = 0; + + out = buf_new(); + key = RSA_new(); + read_pubkey(keybuf, key, NULL); + + buf_prepare(out, RSA_size(key)); + out->length = RSA_public_encrypt(in->length, in->data, out->data, key, + RSA_PKCS1_PADDING); + if (out->length == -1) + out->length = 0, err = -1; + buf_move(in, out); + buf_free(out); + RSA_free(key); + return (err); +} +int buf_crypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc) +{ + des_key_schedule ks1; + des_key_schedule ks2; + des_key_schedule ks3; + des_cblock i; + + assert(enc == ENCRYPT || enc == DECRYPT); + assert((key->length == 16 || key->length == 24) && iv->length == 8); + assert(buf->length % 8 == 0); + + memcpy(i, iv->data, 8); /* leave iv buffer unchanged */ + des_set_key((const_des_cblock *) key->data, ks1); + des_set_key((const_des_cblock *) (key->data + 8), ks2); + if (key->length == 16) + des_set_key((const_des_cblock *) key->data, ks3); + else + des_set_key((const_des_cblock *) (key->data + 16), ks3); + des_ede3_cbc_encrypt(buf->data, buf->data, buf->length, ks1, ks2, ks3, + &i, enc); + return (0); +} + +int buf_3descrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc) +{ + int n = 0; + des_key_schedule ks1; + des_key_schedule ks2; + des_key_schedule ks3; + + assert(enc == ENCRYPT || enc == DECRYPT); + assert(key->length == 24 && iv->length == 8); + + des_set_key((const_des_cblock *) key->data, ks1); + des_set_key((const_des_cblock *) (key->data + 8), ks2); + des_set_key((const_des_cblock *) (key->data + 16), ks3); + des_ede3_cfb64_encrypt(buf->data, buf->data, buf->length, ks1, ks2, ks3, + (des_cblock *) iv->data, &n, enc); + return (0); +} + +int buf_bfcrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc) +{ + int n = 0; + BF_KEY ks; + + if (key == NULL || key->length == 0) + return (-1); + + assert(enc == ENCRYPT || enc == DECRYPT); + assert(key->length == 16 && iv->length == 8); + BF_set_key(&ks, key->length, key->data); + BF_cfb64_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n, + enc == ENCRYPT ? BF_ENCRYPT : BF_DECRYPT); + return (0); +} + +int buf_castcrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc) +{ + int n = 0; + CAST_KEY ks; + + if (key == NULL || key->length == 0) + return (-1); + + assert(enc == ENCRYPT || enc == DECRYPT); + assert(key->length == 16 && iv->length == 8); + CAST_set_key(&ks, 16, key->data); + CAST_cfb64_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n, + enc == ENCRYPT ? CAST_ENCRYPT : CAST_DECRYPT); + return (0); +} + +#ifdef USE_AES +int buf_aescrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc) +{ + int n = 0; + AES_KEY ks; + + if (key == NULL || key->length == 0) + return (-1); + + assert(enc == ENCRYPT || enc == DECRYPT); + assert((key->length == 16 || key->length == 24 || key->length == 32) && iv->length == 16); + AES_set_encrypt_key(key->data, key->length<<3, &ks); + AES_cfb128_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n, + enc == ENCRYPT ? AES_ENCRYPT : AES_DECRYPT); + return (0); +} +#endif /* USE_AES */ + +#ifdef USE_IDEA +int buf_ideacrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc) +{ + int n = 0; + IDEA_KEY_SCHEDULE ks; + + if (key == NULL || key->length == 0) + return (-1); + + assert(enc == ENCRYPT || enc == DECRYPT); + assert(key->length == 16 && iv->length == 8); + idea_set_encrypt_key(key->data, &ks); + idea_cfb64_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n, + enc == ENCRYPT ? IDEA_ENCRYPT : IDEA_DECRYPT); + return (0); +} +#endif /* USE_IDEA */ +#endif /* USE_OPENSSL */ diff --git a/Src/crypto.h b/Src/crypto.h @@ -0,0 +1,48 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Interface to cryptographic library + $Id: crypto.h 934 2006-06-24 13:40:39Z rabbi $ */ + + +#ifndef _CRYPTO_H +#define _CRYPTO_H +#include "mix3.h" + +#ifdef USE_OPENSSL +#include <openssl/opensslv.h> +#if (OPENSSL_VERSION_NUMBER < 0x0903100) +#error "This version of OpenSSL is not supported. Please get a more current version from http://www.openssl.org" +#endif /* version check */ +#include <openssl/des.h> +#include <openssl/blowfish.h> +#include <openssl/md5.h> +#include <openssl/sha.h> +#include <openssl/ripemd.h> +#include <openssl/bn.h> +#include <openssl/dh.h> +#include <openssl/dsa.h> +#include <openssl/rsa.h> +#ifdef USE_IDEA +#include <openssl/idea.h> +#endif /* USE_IDEA */ +#ifdef USE_AES +#include <openssl/aes.h> +#endif /* USE_AES */ +#include <openssl/cast.h> +#include <openssl/rand.h> + +typedef RSA PUBKEY; +typedef RSA SECKEY; + +#else /* end of USE_OPENSSL */ +/* #error "No crypto library." */ +typedef void PUBKEY; +typedef void SECKEY; +#endif /* else not USE_OPENSSL */ + +#endif /* ifndef _CRYPTO_H */ diff --git a/Src/dllmain.c b/Src/dllmain.c @@ -0,0 +1,35 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Mixmaster DLL startup + $Id: dllmain.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#ifdef WIN32 +int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + if(!is_nt_service()) { + rnd_state = RND_WILLSEED; + mix_init(NULL); + if (rnd_state == RND_WILLSEED) + rnd_state = RND_NOTSEEDED; + } + break; + case DLL_PROCESS_DETACH: + if(!is_nt_service()) + mix_exit(); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + return(0); + } + return(1); +} +#endif /* WIN32 */ diff --git a/Src/dummy.c b/Src/dummy.c @@ -0,0 +1,16 @@ +/* Dummy function for programs that don't use menuutil.c */ + +#include "mix3.h" + +int menu_getuserpass(BUFFER *b, int i) +{ + return -1; +} + +void cl(int y, int x) +{} + +int download_stats(char *sourcename) +{ + return -1; +} diff --git a/Src/keymgt.c b/Src/keymgt.c @@ -0,0 +1,434 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Key management + $Id: keymgt.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <string.h> +#include <time.h> +#include <assert.h> + +int getv2seckey(byte keyid[], BUFFER *key); +static int getv2pubkey(byte keyid[], BUFFER *key); + +int db_getseckey(byte keyid[], BUFFER *key) +{ + if (getv2seckey(keyid, key) == -1) + return (-1); + else + return (0); +} + +int db_getpubkey(byte keyid[], BUFFER *key) +{ + if (getv2pubkey(keyid, key) == -1) + return (-1); + else + return (0); +} + +/* now accepts NULL keyid too, with NULL keyid any key + * will be matched, with valid passphrase of course */ +int getv2seckey(byte keyid[], BUFFER *key) +{ + FILE *keyring; + BUFFER *iv, *pass, *temp; + char idstr[KEY_ID_LEN+2]; + char line[LINELEN]; + int err = -1; + char *res; + time_t created, expires; + + pass = buf_new(); + iv = buf_new(); + temp = buf_new(); + if (keyid) + id_encode(keyid, idstr); + else + idstr[0] = 0; + strcat(idstr, "\n"); + if ((keyring = mix_openfile(SECRING, "r")) == NULL) { + errlog(ERRORMSG, "No secret key file!\n"); + } else { + while (err == -1) { + buf_clear(key); + if (fgets(line, sizeof(line), keyring) == NULL) + break; + if (strleft(line, begin_key)) { + expires = 0; + created = 0; + do { + res = fgets(line, sizeof(line), keyring); + if (strileft(line, "created:")) { + created = parse_yearmonthday(strchr(line, ':')+1); + if (created == -1) + created = 0; + } else if (strileft(line, "expires:")) { + expires = parse_yearmonthday(strchr(line, ':')+1); + if (expires == -1) + expires = 0; + } + /* Fetch lines until we fail or get a non-header line */ + } while ( res != NULL && strchr(line, ':') != NULL ); + if (res == NULL) + break; + if (keyid && (strncmp(line, idstr, KEY_ID_LEN) != 0)) + continue; + if (created != 0 && (created > time(NULL))) { + errlog(ERRORMSG, "Key is not valid yet (creation date in the future): %s", idstr); + break; + } + if (expires != 0 && (expires + KEYGRACEPERIOD < time(NULL))) { + errlog(ERRORMSG, "Key is expired: %s", idstr); + break; + } + fgets(line, sizeof(line), keyring); + fgets(line, sizeof(line), keyring); + buf_sets(iv, line); + decode(iv, iv); + for (;;) { + if (fgets(line, sizeof(line), keyring) == NULL) + break; + if (strleft(line, end_key)) { + if (decode(key, key) == -1) { + errlog(ERRORMSG, "Corrupt secret key.\n"); + break; + } + buf_sets(pass, PASSPHRASE); + digest_md5(pass, pass); + buf_crypt(key, pass, iv, DECRYPT); + err = check_seckey(key, keyid); + if (err == -1) + errlog(ERRORMSG, "Corrupt secret key. Bad passphrase?\n"); + break; + } + buf_append(key, line, strlen(line) - 1); + } + break; + } + } + fclose(keyring); + } + + buf_free(pass); + buf_free(iv); + buf_free(temp); + return (err); +} + +static int getv2pubkey(byte keyid[], BUFFER *key) +{ + FILE *keyring; + BUFFER *b, *temp, *iv; + char idstr[KEY_ID_LEN+2]; + char line[LINELEN]; + int err = 0; + + b = buf_new(); + iv = buf_new(); + temp = buf_new(); + id_encode(keyid, idstr); + if ((keyring = mix_openfile(PUBRING, "r")) == NULL) { + errlog(ERRORMSG, "Can't open %s!\n", PUBRING); + err = -1; + goto end; + } + for (;;) { + if (fgets(line, sizeof(line), keyring) == NULL) + break; + if (strleft(line, begin_key)) { + if (fgets(line, sizeof(line), keyring) == NULL) + break; + if ((strlen(line) > 0) && (line[strlen(line)-1] == '\n')) + line[strlen(line)-1] = '\0'; + if ((strlen(line) > 0) && (line[strlen(line)-1] == '\r')) + line[strlen(line)-1] = '\0'; + if (strncmp(line, idstr, KEY_ID_LEN) != 0) + continue; + fgets(line, sizeof(line), keyring); /* ignore length */ + for (;;) { + if (fgets(line, sizeof(line), keyring) == NULL) + goto done; + if (strleft(line, end_key)) + goto done; + buf_append(key, line, strlen(line)); + } + break; + } + } +done: + fclose(keyring); + + if (key->length == 0) { + errlog(ERRORMSG, "No such public key: %s\n", idstr); + err = -1; + goto end; + } + err = decode(key, key); + if (err != -1) + err = check_pubkey(key, keyid); + if (err == -1) + errlog(ERRORMSG, "Corrupt public key %s\n", idstr); +end: + buf_free(b); + buf_free(iv); + buf_free(temp); + return (err); +} + +int key(BUFFER *out) +{ + int err = -1; + FILE *f; + BUFFER *tmpkey; + + tmpkey = buf_new(); + + buf_sets(out, "Subject: Remailer key for "); + buf_appends(out, SHORTNAME); + buf_appends(out, "\n\n"); + + keymgt(0); + + conf_premail(out); + buf_nl(out); + +#ifdef USE_PGP + if (PGP) { + if (pgp_latestkeys(tmpkey, PGP_ES_RSA) == 0) { + buf_appends(out, "Here is the RSA PGP key:\n\n"); + buf_cat(out, tmpkey); + buf_nl(out); + err = 0; + } + if (pgp_latestkeys(tmpkey, PGP_S_DSA) == 0) { + buf_appends(out, "Here is the DSA PGP key:\n\n"); + buf_cat(out, tmpkey); + buf_nl(out); + err = 0; + } + } +#endif /* USE_PGP */ + if (MIX) { + if ((f = mix_openfile(KEYFILE, "r")) != NULL) { + buf_appends(out, "Here is the Mixmaster key:\n\n"); + buf_appends(out, "=-=-=-=-=-=-=-=-=-=-=-=\n"); + buf_read(out, f); + buf_nl(out); + fclose(f); + err = 0; + } + } + if (err == -1 && UNENCRYPTED) { + buf_appends(out, "The remailer accepts unencrypted messages.\n"); + err = 0; + } + if (err == -1) + errlog(ERRORMSG, "Cannot create remailer keys!"); + + buf_free(tmpkey); + + return (err); +} + +int adminkey(BUFFER *out) +{ + int err = -1; + FILE *f; + + buf_sets( out, "Subject: Admin key for the " ); + buf_appends( out, SHORTNAME ); + buf_appends( out, " remailer\n\n" ); + + if ( (f = mix_openfile( ADMKEYFILE, "r" )) != NULL ) { + buf_read( out, f ); + buf_nl( out ); + fclose( f ); + err = 0; + } + + if ( err == -1 ) + errlog( ERRORMSG, "Can not read admin key file!\n" ); + + return err; +} + +int v2keymgt(int force) +/* + * Mixmaster v2 Key Management + * + * This function triggers creation of mix keys (see parameter force) which are + * stored in secring.mix. One public mix key is also written to key.txt. This + * is the key with the latest expiration date (keys with no expiration date + * are always considered newer if they appear later in the secret mix file + * - key creation appends keys). + * + * force: + * 0, 1: create key when necessary: + * - no key exists as of yet + * - old keys are due to expire/already expired + * 2: always create a new mix key. + * + * (force = 0 is used in mix_daily, and before remailer-key replies) + * (force = 1 is used by mixmaster -K) + * (force = 2 is used by mixmaster -G) + */ +{ + FILE *keyring, *f; + char line[LINELEN]; + byte k1[16], k1_found[16]; + BUFFER *b, *temp, *iv, *pass, *pk, *pk_found; + int err = 0; + int found, foundnonexpiring; + time_t created, expires, created_found, expires_found; + char *res; + + b = buf_new(); + temp = buf_new(); + iv = buf_new(); + pass = buf_new(); + pk = buf_new(); + pk_found = buf_new(); + + foundnonexpiring = 0; + for (;;) { + found = 0; + created_found = 0; + expires_found = 0; + + keyring = mix_openfile(SECRING, "r"); + if (keyring != NULL) { + for (;;) { + if (fgets(line, sizeof(line), keyring) == NULL) + break; + if (strleft(line, begin_key)) { + expires = 0; + created = 0; + do { + res = fgets(line, sizeof(line), keyring); + if (strileft(line, "created:")) { + created = parse_yearmonthday(strchr(line, ':')+1); + if (created == -1) + created = 0; + } else if (strileft(line, "expires:")) { + expires = parse_yearmonthday(strchr(line, ':')+1); + if (expires == -1) + expires = 0; + } + /* Fetch lines until we fail or get a non-header line */ + } while ( res != NULL && strchr(line, ':') != NULL ); + if (res == NULL) + break; + if (((created != 0) && (created > time(NULL))) || + ((expires != 0) && (expires < time(NULL)))) { + /* Key already is expired or has creation date in the future */ + continue; + } + id_decode(line, k1); + fgets(line, sizeof(line), keyring); + if (fgets(line, sizeof(line), keyring) == NULL) + break; + buf_sets(iv, line); + decode(iv, iv); + buf_reset(b); + for (;;) { + if (fgets(line, sizeof(line), keyring) == NULL) + break; + if (strleft(line, end_key)) + break; + buf_append(b, line, strlen(line) - 1); + } + if (decode(b, b) == -1) + break; + buf_sets(temp, PASSPHRASE); + digest_md5(temp, pass); + buf_crypt(b, pass, iv, DECRYPT); + buf_clear(pk); + if (seckeytopub(pk, b, k1) == 0) { + found = 1; + if (expires == 0 || (expires - KEYOVERLAPPERIOD >= time(NULL))) + foundnonexpiring = 1; + if (expires == 0 || (expires_found <= expires)) { + buf_clear(pk_found); + buf_cat(pk_found, pk); + memcpy(&k1_found, &k1, sizeof(k1)); + expires_found = expires; + created_found = created; + } + } + } + } + fclose(keyring); + } + + if (!foundnonexpiring || (force == 2)) { + v2createkey(); + foundnonexpiring = 1; + force = 1; + } else + break; + }; + + if (found) { + if ((f = mix_openfile(KEYFILE, "w")) != NULL) { + id_encode(k1_found, line); + fprintf(f, "%s %s %s %s:%s %s%s", SHORTNAME, + REMAILERADDR, line, mixmaster_protocol, VERSION, + MIDDLEMAN ? "M" : "", + NEWS[0] == '\0' ? "C" : (strchr(NEWS, '@') ? "CNm" : "CNp")); + if (created_found) { + struct tm *gt; + gt = gmtime(&created_found); + strftime(line, LINELEN, "%Y-%m-%d", gt); + fprintf(f, " %s", line); + if (expires_found) { + struct tm *gt; + gt = gmtime(&expires_found); + strftime(line, LINELEN, "%Y-%m-%d", gt); + fprintf(f, " %s", line); + } + } + fprintf(f, "\n\n%s\n", begin_key); + id_encode(k1_found, line); + fprintf(f, "%s\n258\n", line); + encode(pk_found, 40); + buf_write(pk_found, f); + fprintf(f, "%s\n\n", end_key); + fclose(f); + } + } else + err = -1; + + buf_free(b); + buf_free(temp); + buf_free(iv); + buf_free(pass); + buf_free(pk); + buf_free(pk_found); + + return (err); +} + +int keymgt(int force) +{ + /* force = 0: write key file if there is none + force = 1: update key file + force = 2: generate new key */ + int err = 0; + + if (REMAIL || force == 2) { + if (MIX && (err = v2keymgt(force)) == -1) + err = -1; +#ifdef USE_PGP + if (PGP && (err = pgp_keymgt(force)) == -1) + err = -1; +#endif /* USE_PGP */ + } + return (err); +} diff --git a/Src/mail.c b/Src/mail.c @@ -0,0 +1,898 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Socket-based mail transport services + $Id: mail.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(UNIX) && defined(USE_SOCK) +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#endif /* defined(UNIX) && defined(USE_SOCK) */ + +#include <fcntl.h> +#include <time.h> +#include <sys/stat.h> +#include <errno.h> + + +int sendinfofile(char *name, char *logname, BUFFER *address, BUFFER *header) +{ + FILE *f = NULL, *log = NULL; + BUFFER *msg, *addr; + char line[LINELEN]; + int ret = -1; + + if (bufeq(address, ANONNAME)) + return (0); /* don't reply to our own anon messages */ + f = mix_openfile(name, "r"); + if (f == NULL) + return (-1); + + addr = buf_new(); + rfc822_addr(address, addr); + if (addr->length == 0) + buf_set(addr, address), buf_nl(addr); + + if (logname != NULL) { + if ((log = mix_openfile(logname, "r+")) != NULL) { + /* log recipients to prevent mail loop */ + while (fgets(line, sizeof(line), log) != NULL) + if (strieq(line, addr->data)) + goto end; + } else if ((log = mix_openfile(logname, "w")) == NULL) { + errlog(ERRORMSG, "Can't create %s.\n", logname); + ret = -1; + goto end; + } + fprintf(log, "%s", addr->data); + } + msg = buf_new(); + if (header) + buf_cat(msg, header), buf_nl(msg); + while (fgets(line, sizeof(line), f) != NULL) { + if (streq(line, "DESTINATION-BLOCK\n")) + buf_appendf(msg, "destination-block %b", addr); + else + buf_appends(msg, line); + } + ret = sendmail(msg, REMAILERNAME, address); + buf_free(msg); +end: + if (f) + fclose(f); + if (log) + fclose(log); + buf_free(addr); + return (ret); +} + +int smtpsend(BUFFER *head, BUFFER *message, char *from); + + +int sendmail_loop(BUFFER *message, char *from, BUFFER *address) +{ + BUFFER *msg; + int err; + + msg = buf_new(); + buf_appendf(msg, "X-Loop: %s\n", REMAILERADDR); + buf_cat(msg, message); + err = sendmail(msg, from, address); + buf_free(msg); + + return(err); +} + +/* Returns true if more than one of the recipients in the + * rcpt buffer is a remailer + */ +int has_more_than_one_remailer(BUFFER *rcpts) +{ + BUFFER *newlinelist; + BUFFER *line; + int remailers = 0; + REMAILER type1[MAXREM]; + REMAILER type2[MAXREM]; + int num1; + int num2; + int i; + + newlinelist = buf_new(); + line = buf_new(); + + num1 = t1_rlist(type1, NULL); + num2 = mix2_rlist(type2, NULL); + + rfc822_addr(rcpts, newlinelist); + + while (buf_getline(newlinelist, line) != -1) { + int found = 0; + printf("%s\n", line->data); + + for (i = 0; i < num2; i++) + if (strcmp(type2[i].addr, line->data) == 0) { + found = 1; + break; + } + if (!found) + for (i = 0; i < num1; i++) + if (strcmp(type1[i].addr, line->data) == 0) { + found = 1; + break; + } + if (found) + remailers++; + } + printf("found %d\n", remailers); + + buf_free(newlinelist); + buf_free(line); + + return(remailers > 1); +} + +int sendmail(BUFFER *message, char *from, BUFFER *address) +{ + /* returns: 0: ok 1: problem, try again -1: failed */ + + BUFFER *head, *block, *rcpt; + FILE *f; + int err = -1; + int rcpt_cnt; + + head = buf_new(); + rcpt = buf_new(); + + block = readdestblk( ); + if ( !block ) block = buf_new( ); + + if (address != NULL && + (address->length == 0 || doblock(address, block, 1) == -1)) + goto end; + + if (from != NULL) { + buf_setf(head, "From: %s", from); + hdr_encode(head, 255); + buf_nl(head); + } + if (address != NULL) + buf_appendf(head, "To: %b\n", address); + + if (PRECEDENCE[0]) + buf_appendf(head, "Precedence: %s\n", PRECEDENCE); + + buf_rewind(message); + + /* search recipient addresses */ + if (address == NULL) { + BUFFER *field, *content; + field = buf_new(); + content = buf_new(); + + rcpt_cnt = 0; + while (buf_getheader(message, field, content) == 0) { + if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) { + int thislinercpts = 1; + char *tmp = content->data; + while ((tmp = strchr(tmp+1, ','))) + thislinercpts ++; + rcpt_cnt += thislinercpts; + + if ( rcpt->data[0] ) + buf_appends(rcpt, ", "); + buf_cat(rcpt, content); + } + } + buf_free(field); + buf_free(content); + } else if (address->data[0]) { + char *tmp = address->data; + rcpt_cnt = 1; + while ((tmp = strchr(tmp+1, ','))) + rcpt_cnt ++; + + buf_set(rcpt, address); + } else + rcpt_cnt = 0; + + buf_rewind(message); + + if ( ! rcpt_cnt ) { + errlog(NOTICE, "No recipients found.\n"); + err = 0; + } else if ( rcpt_cnt > MAXRECIPIENTS ) { + errlog(NOTICE, "Too many recipients. Dropping message.\n"); + err = 0; + } else if ( rcpt_cnt > 1 && has_more_than_one_remailer(rcpt) ) { + errlog(NOTICE, "Message is destined to more than one remailer. Dropping.\n"); + err = 0; + } else if ( REMAIL && strcmp(REMAILERADDR, rcpt->data) == 0) { + buf_cat(head, message); + errlog(LOG, "Message loops back to us; storing in pool rather than sending it.\n"); + err = pool_add(head, "inf"); + } else if (SMTPRELAY[0]) + err = smtpsend(head, message, from); + else if (strieq(SENDMAIL, "outfile")) { + char path[PATHMAX]; + FILE *f = NULL; +#ifdef SHORTNAMES + int i; + for (i = 0; i < 10000; i++) { + snprintf(path, PATHMAX, "%s%cout%i.txt", POOLDIR, DIRSEP, i); + f = fopen(path, "r"); + if (f) + fclose(f); + else + break; + } + f = fopen(path, "w"); +#else /* end of SHORTNAMES */ + static unsigned long namecounter = 0; + struct stat statbuf; + int count; + char hostname[64]; + + hostname[0] = '\0'; + gethostname(hostname, 63); + hostname[63] = '\0'; + + /* Step 2: Stat the file. Wait for ENOENT as a response. */ + for (count = 0;; count++) { + snprintf(path, PATHMAX, "%s%cout.%lu.%u_%lu.%s,S=%lu.txt", + POOLDIR, DIRSEP, time(NULL), getpid(), namecounter++, hostname, head->length + message->length); + + if (stat(path, &statbuf) == 0) + errno = EEXIST; + else if (errno == ENOENT) { /* create the file (at least try) */ + f = fopen(path, "w"); + if (f != NULL) + break; /* we managed to open the file */ + } + if (count > 5) + break; /* Too many retries - give up */ + sleep(2); /* sleep and retry */ + } +#endif /* else not SHORTNAMES */ + if (f != NULL) { + err = buf_write(head, f); + err = buf_write(message, f); + fclose(f); + } else + errlog(ERRORMSG, "Can't create %s!\n", path); + } else { + if (SENDANONMAIL[0] != '\0' && (from == NULL || streq(from, ANONNAME))) + f = openpipe(SENDANONMAIL); + else + f = openpipe(SENDMAIL); + if (f != NULL) { + err = buf_write(head, f); + err = buf_write(message, f); + closepipe(f); + } + } + if (err != 0) { + errlog(ERRORMSG, "Unable to execute sendmail. Check path!\n"); + err = 1; /* error while sending, retry later */ + } + +end: + buf_free(block); + buf_free(head); + buf_free(rcpt); + return (err); +} + +/* socket communication **********************************************/ + +#ifdef USE_SOCK +#ifdef WIN32 +WSADATA w; + +int sock_init() +{ + if (WSAStartup(MAKEWORD(2, 0), &w) != 0) { + errlog(ERRORMSG, "Unable to initialize WINSOCK.\n"); + return 0; + } + return 1; +} + +void sock_exit(void) +{ + WSACleanup(); +} +#endif /* WIN32 */ + +SOCKET opensocket(char *hostname, int port) +{ + struct hostent *hp; + struct sockaddr_in server; + SOCKET s; + + if ((hp = gethostbyname(hostname)) == NULL) + return (INVALID_SOCKET); + + memset((char *) &server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = *(unsigned long *) hp->h_addr; + server.sin_port = htons((unsigned short) port); + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s != INVALID_SOCKET) + if (connect(s, (struct sockaddr *) &server, sizeof(server)) < 0) { + closesocket(s); + return (INVALID_SOCKET); + } + return (s); +} + +#ifndef WIN32 +int closesocket(SOCKET s) +{ + return (close(s)); +} +#endif /* ifndef WIN32 */ + +int sock_getline(SOCKET s, BUFFER *line) +{ + char c; + int ok; + + buf_clear(line); + while ((ok = recv(s, &c, 1, 0)) > 0) { + if (c == '\n') + break; + if (c != '\r') + buf_appendc(line, c); + } + if (ok <= 0) + return (-1); + if (line->length == 0) + return (1); + return (0); +} + +int sock_cat(SOCKET s, BUFFER *b) +{ + int p = 0, n; + + do { + n = send(s, b->data, b->length, 0); + if (n < 0) + return (-1); + p += n; + } while (p < b->length); + return (0); +} +#else /* end of USE_SOCK */ +SOCKET opensocket(char *hostname, int port) +{ + return (INVALID_SOCKET); +} + +int closesocket(SOCKET s) +{ + return (INVALID_SOCKET); +} + +int sock_getline(SOCKET s, BUFFER *line) +{ + return (-1); +} + +int sock_cat(SOCKET s, BUFFER *b) +{ + return (-1); +} +#endif /* else not USE_SOCK */ + +/* send messages by SMTP ************************************************/ + +static int sock_getsmtp(SOCKET s, BUFFER *response) +{ + int ret; + BUFFER *line; + line = buf_new(); + + buf_clear(response); + do { + ret = sock_getline(s, line); + buf_cat(response, line); + } while (line->length >= 4 && line->data[3] == '-'); + buf_free(line); + return (ret); +} + +SOCKET smtp_open(void) +{ + int s = INVALID_SOCKET; + int esmtp = 0; + BUFFER *line; + +#ifdef USE_SOCK + if (SMTPRELAY[0] != '\0') + s = opensocket(SMTPRELAY, 25); + if (s != INVALID_SOCKET) { + line = buf_new(); + sock_getsmtp(s, line); + if (bufifind(line, "ESMTP")) + esmtp = 1; + if (line->data[0] != '2') { + errlog(ERRORMSG, "SMTP relay not ready. %b\n", line); + closesocket(s); + s = INVALID_SOCKET; + } else { + errlog(DEBUGINFO, "Opening SMTP connection.\n"); + if (esmtp) + buf_sets(line, "EHLO "); + else + buf_sets(line, "HELO "); + if (HELONAME[0]) + buf_appends(line, HELONAME); + else if (strchr(ENVFROM, '@')) + buf_appends(line, strchr(ENVFROM, '@') + 1); + else { + struct sockaddr_in sa; + int len = sizeof(sa); + struct hostent *hp; + + if (getsockname(s, (struct sockaddr *) &sa, &len) == 0 && + (hp = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr), + AF_INET)) != NULL) + buf_appends(line, (char *) hp->h_name); + else if (strchr(REMAILERADDR, '@')) + buf_appends(line, strchr(REMAILERADDR, '@') + 1); + else + buf_appends(line, SHORTNAME); + } + buf_chop(line); + buf_appends(line, "\r\n"); + sock_cat(s, line); + sock_getsmtp(s, line); + if (line->data[0] != '2') { + errlog(ERRORMSG, "SMTP relay refuses HELO: %b\n", line); + closesocket(s); + s = INVALID_SOCKET; + } else if (SMTPUSERNAME[0] && esmtp && bufifind(line, "AUTH") && bufifind(line, "LOGIN")) { + buf_sets(line, "AUTH LOGIN\r\n"); + sock_cat(s, line); + sock_getsmtp(s, line); + if (!bufleft(line, "334")) { + errlog(ERRORMSG, "SMTP AUTH fails: %b\n", line); + goto err; + } + buf_sets(line, SMTPUSERNAME); + encode(line, 0); + buf_appends(line, "\r\n"); + sock_cat(s, line); + sock_getsmtp(s, line); + if (!bufleft(line, "334")) { + errlog(ERRORMSG, "SMTP username rejected: %b\n", line); + goto err; + } + buf_sets(line, SMTPPASSWORD); + encode(line, 0); + buf_appends(line, "\r\n"); + sock_cat(s, line); + sock_getsmtp(s, line); + if (!bufleft(line, "235")) + errlog(ERRORMSG, "SMTP authentication failed: %b\n", line); + } + } +err: + buf_free(line); + } +#endif /* USE_SOCK */ + return (s); +} + +int smtp_close(SOCKET s) +{ + BUFFER *line; + int ret = -1; + +#ifdef USE_SOCK + line = buf_new(); + buf_sets(line, "QUIT\r\n"); + sock_cat(s, line); + if (sock_getsmtp(s, line) == 0 && line->data[0] == '2') { + errlog(DEBUGINFO, "Closing SMTP connection.\n"); + ret = 0; + } else + errlog(WARNING, "SMTP quit failed: %b\n", line); + closesocket(s); + buf_free(line); +#endif /* USE_SOCK */ + return (ret); +} + +int smtp_send(SOCKET relay, BUFFER *head, BUFFER *message, char *from) +{ + BUFFER *rcpt, *line, *field, *content; + int ret = -1; + +#ifdef USE_SOCK + line = buf_new(); + field = buf_new(); + content = buf_new(); + rcpt = buf_new(); + + while (buf_getheader(head, field, content) == 0) + if (bufieq(field, "to")) +#ifdef BROKEN_MTA + if (!bufifind(rcpt, content->data)) + /* Do not add the same recipient twice. + Needed for brain-dead MTAs. */ +#endif /* BROKEN_MTA */ + rfc822_addr(content, rcpt); + buf_rewind(head); + + while (buf_isheader(message) && buf_getheader(message, field, content) == 0) { + if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) { +#ifdef BROKEN_MTA + if (!bufifind(rcpt, content->data)) + /* Do not add the same recipient twice. + Needed for brain-dead MTAs. */ +#endif /* BROKEN_MTA */ + rfc822_addr(content, rcpt); + } + if (!bufieq(field, "bcc")) + buf_appendheader(head, field, content); + } + buf_nl(head); + + buf_clear(content); + if (from) { + buf_sets(line, from); + rfc822_addr(line, content); + buf_chop(content); + } + if (bufieq(content, REMAILERADDR) || bufieq(content, ANONADDR)) + buf_clear(content); + if (content->length == 0) + buf_sets(content, ENVFROM[0] ? ENVFROM : ANONADDR); + + buf_setf(line, "MAIL FROM:<%b>\r\n", content); + sock_cat(relay, line); + sock_getsmtp(relay, line); + if (!line->data[0] == '2') { + errlog(ERRORMSG, "SMTP relay does not accept mail: %b\n", line); + goto end; + } + while (buf_getline(rcpt, content) == 0) { + buf_setf(line, "RCPT TO:<%b>\r\n", content); + sock_cat(relay, line); + sock_getsmtp(relay, line); + if (bufleft(line, "421")) { + errlog(ERRORMSG, "SMTP relay error: %b\n", line); + goto end; + } + if (bufleft(line, "530")) { + errlog(ERRORMSG, "SMTP authentication required: %b\n", line); + goto end; + } + } + + buf_sets(line, "DATA\r\n"); + sock_cat(relay, line); + sock_getsmtp(relay, line); + if (!bufleft(line, "354")) { + errlog(WARNING, "SMTP relay does not accept message: %b\n", line); + goto end; + } + while (buf_getline(head, line) >= 0) { + buf_appends(line, "\r\n"); + if (bufleft(line, ".")) { + buf_setf(content, ".%b", line); + buf_move(line, content); + } + sock_cat(relay, line); + } + while (buf_getline(message, line) >= 0) { + buf_appends(line, "\r\n"); + if (bufleft(line, ".")) { + buf_setf(content, ".%b", line); + buf_move(line, content); + } + sock_cat(relay, line); + } + buf_sets(line, ".\r\n"); + sock_cat(relay, line); + sock_getsmtp(relay, line); + if (bufleft(line, "2")) + ret = 0; + else + errlog(WARNING, "SMTP relay will not send message: %b\n", line); +end: + buf_free(line); + buf_free(field); + buf_free(content); + buf_free(rcpt); +#endif /* USE_SOCK */ + return (ret); +} + +static SOCKET sendmail_state = INVALID_SOCKET; + +void sendmail_begin(void) +{ + /* begin mail sending session */ + if (sendmail_state == INVALID_SOCKET) + sendmail_state = smtp_open(); +} +void sendmail_end(void) +{ + /* end mail sending session */ + if (sendmail_state != INVALID_SOCKET) { + smtp_close(sendmail_state); + sendmail_state = INVALID_SOCKET; + } +} + +int smtpsend(BUFFER *head, BUFFER *message, char *from) +{ + SOCKET s; + int ret = -1; + + if (sendmail_state != INVALID_SOCKET) + ret = smtp_send(sendmail_state, head, message, from); + else { + s = smtp_open(); + if (s != INVALID_SOCKET) { + ret = smtp_send(s, head, message, from); + smtp_close(s); + } + } + return (ret); +} + +/* retrieve mail with POP3 **********************************************/ +#ifdef USE_SOCK +int pop3_close(SOCKET s); + +#define POP3_ANY 0 +#define POP3_APOP 1 +#define POP3_PASS 2 + +SOCKET pop3_open(char *user, char *host, char *pass, int auth) +{ + SOCKET server = INVALID_SOCKET; + BUFFER *line; + int authenticated = 0; + char md[33]; + int c; + + line = buf_new(); + server = opensocket(host, 110); + if (server == INVALID_SOCKET) + errlog(NOTICE, "Can't connect to POP3 server %s.\n", host); + else { + sock_getline(server, line); + if (!bufleft(line, "+")) { + errlog(WARNING, "No POP3 service at %s.\n", host); + closesocket(server); + server = INVALID_SOCKET; + } + } + if (server != INVALID_SOCKET) { + errlog(DEBUGINFO, "Opening POP3 connection to %s.\n", host); + do + c = buf_getc(line); + while (c != '<' && c != -1); + while (c != '>' && c != -1) { + buf_appendc(line, c); + c = buf_getc(line); + } + if (c == '>' && (auth == POP3_ANY || auth == POP3_APOP)) { + buf_appendc(line, c); + buf_appends(line, pass); + digest_md5(line, line); + id_encode(line->data, md); + buf_setf(line, "APOP %s %s\r\n", user, md); + sock_cat(server, line); + sock_getline(server, line); + if (bufleft(line, "+")) + authenticated = 1; + else { + errlog(auth == POP3_APOP ? ERRORMSG : NOTICE, + "POP3 APOP auth at %s failed: %b\n", host, line); + buf_sets(line, "QUIT\r\n"); + sock_cat(server, line); + closesocket(server); + server = pop3_open(user, host, pass, POP3_PASS); + goto end; + } + } + if (!authenticated) { + buf_setf(line, "USER %s\r\n", user); + sock_cat(server, line); + sock_getline(server, line); + if (!bufleft(line, "+")) + errlog(ERRORMSG, "POP3 USER command at %s failed: %b\n", host, line); + else { + buf_setf(line, "PASS %s\r\n", pass); + sock_cat(server, line); + sock_getline(server, line); + if (bufleft(line, "+")) + authenticated = 1; + else + errlog(ERRORMSG, "POP3 auth at %s failed: %b\n", host, line); + } + } + if (!authenticated) { + pop3_close(server); + closesocket(server); + server = INVALID_SOCKET; + } + } + end: + buf_free(line); + return (server); +} + +int pop3_close(SOCKET s) +{ + BUFFER *line; + int ret = -1; + + line = buf_new(); + buf_sets(line, "QUIT\r\n"); + sock_cat(s, line); + sock_getline(s, line); + if (bufleft(line, "+")) { + ret = 0; + errlog(DEBUGINFO, "Closing POP3 connection.\n"); + } else + errlog(ERRORMSG, "POP3 QUIT failed:\n", line->data); + buf_free(line); + return (ret); +} + +int pop3_stat(SOCKET s) +{ + BUFFER *line; + int val = -1; + + line = buf_new(); + buf_sets(line, "STAT\r\n"); + sock_cat(s, line); + sock_getline(s, line); + if (bufleft(line, "+")) + sscanf(line->data, "+%*s %d", &val); + buf_free(line); + return (val); +} + +int pop3_list(SOCKET s, int n) +{ + BUFFER *line; + int val = -1; + + line = buf_new(); + buf_setf(line, "LIST %d\r\n", n); + sock_cat(s, line); + sock_getline(s, line); + if (bufleft(line, "+")) + sscanf(line->data, "+%*s %d", &val); + buf_free(line); + return (val); +} + +int pop3_dele(SOCKET s, int n) +{ + BUFFER *line; + int ret = 0; + + line = buf_new(); + buf_setf(line, "DELE %d\r\n", n); + sock_cat(s, line); + sock_getline(s, line); + if (!bufleft(line, "+")) + ret = -1; + buf_free(line); + return (ret); +} + +int pop3_retr(SOCKET s, int n, BUFFER *msg) +{ + BUFFER *line; + int ret = -1; + + line = buf_new(); + buf_clear(msg); + buf_setf(line, "RETR %d\r\n", n); + sock_cat(s, line); + sock_getline(s, line); + if (bufleft(line, "+")) { + for (;;) { + if (sock_getline(s, line) == -1) + break; + if (bufeq(line, ".")) { + ret = 0; + break; + } else if (bufleft(line, ".")) { + buf_append(msg, line->data + 1, line->length - 1); + } else + buf_cat(msg, line); + buf_nl(msg); + } + } + buf_free(line); + return (ret); +} + +void pop3get(void) +{ + FILE *f; + char cfg[LINELEN], user[LINELEN], host[LINELEN], pass[LINELEN], auth[5]; + SOCKET server; + BUFFER *line, *msg; + int i = 0, num = 0; + + line = buf_new(); + msg = buf_new(); + f = mix_openfile(POP3CONF, "r"); + if (f != NULL) + while (fgets(cfg, sizeof(cfg), f) != NULL) { + if (cfg[0] == '#') + continue; + if (strchr(cfg, '@')) + strchr(cfg, '@')[0] = ' '; + if (sscanf(cfg, "%127s %127s %127s %4s", user, host, pass, auth) < 3) + continue; + i = POP3_ANY; + if (strileft(auth, "apop")) + i = POP3_APOP; + if (strileft(auth, "pass")) + i = POP3_PASS; + server = pop3_open(user, host, pass, i); + if (server != INVALID_SOCKET) { + num = pop3_stat(server); + if (num < 0) + errlog(WARNING, "POP3 protocol error at %s.\n", host); + else if (num == 0) + errlog(DEBUGINFO, "No mail at %s.\n", host); + else + for (i = 1; i <= num; i++) { + if (POP3SIZELIMIT > 0 && + pop3_list(server, i) > POP3SIZELIMIT * 1024) { + errlog(WARNING, "Over size message on %s.", host); + if (POP3DEL == 1) + pop3_dele(server, i); + } else { + if (pop3_retr(server, i, msg) == 0 && + pool_add(msg, "inf") == 0) + pop3_dele(server, i); + else { + errlog(WARNING, "POP3 error while getting mail from %s.", + host); + closesocket(server); + goto end; + } + } + } + pop3_close(server); + closesocket(server); + } + } + end: + if (f != NULL) + fclose(f); + buf_free(line); + buf_free(msg); +} +#endif /* USE_SOCK */ diff --git a/Src/maildir.c b/Src/maildir.c @@ -0,0 +1,323 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Maildir support routines + $Id: $ */ + + +/* Maildir support for Mixmaster 3 - see + http://www.qmail.org/man/man5/maildir.html and + http://cr.yp.to/proto/maildir.html + + Added by and (C) 2001 Doobee R. Tzeck + drt@un.bewaff.net - http://c0re.jp/ + + To test it try: + $ gcc maildir.c -DUNITTEST -o test_maildir + $ ./test_maildir + this should print a single line saying "OK" +*/ + +#include "mix3.h" + +#ifdef WIN32 +#include <io.h> +#include <direct.h> +#include <process.h> +#define S_IWUSR _S_IWRITE +#define S_IRUSR _S_IREAD +#else /* end of WIN32 */ +#include <unistd.h> +#endif /* else not WIN32 */ +#include <fcntl.h> +#include <time.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <stdarg.h> +#include <assert.h> + +#if defined(S_IFDIR) && !defined(S_ISDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif /* defined(S_IFDIR) && !defined(S_ISDIR) */ + +#ifndef SHORTNAMES + +static unsigned long namecounter = 0; + +int checkDirectory(char *dir, char *append, int create) { + char tmp[PATHMAX]; + struct stat buf; + int err; + + tmp[0] = '\0'; + strcatn(tmp, dir, PATHMAX); + if (append) + strcatn(tmp, append, PATHMAX); + + err = stat(tmp, &buf); + if (err == -1) { + if (create) { +#ifndef POSIX + err = mkdir(tmp); +#else /* end of not POSIX */ + err = mkdir(tmp, S_IRWXU); +#endif /* else if POSIX */ + if (err == 0) + errlog(NOTICE, "Creating directory %s.\n", tmp); + } else + err = 1; + } else if (!S_ISDIR(buf.st_mode)) + err = -1; + + return err; +} + +/* Write "message" to "maildir", retunr 0 on success, -1 on failure */ +#define MAX_BASENAME 113 /* actual length should be smaller than 111 bytes */ +#define MAX_SUBNAME 123 /* actual length should be smaller than 115 bytes */ +int maildirWrite(char *maildir, BUFFER *message, int create) { + int fd; + int count; + int returnValue; + char hostname[64]; + struct stat statbuf; + char basename[MAX_BASENAME]; + char tmpname[MAX_SUBNAME]; + char newname[MAX_SUBNAME]; + int messagesize; + char olddirectory[PATHMAX] = ""; + char normalizedmaildir[PATHMAX]; + + /* Declare a handler for SIGALRM so we can time out. */ + /* set_handler(SIGALRM, alarm_handler); */ + /* alarm(86400); */ + + hostname[0] = '\0'; + gethostname(hostname, 63); + hostname[63] = '\0'; + + mixfile(normalizedmaildir, maildir); + if ((checkDirectory(normalizedmaildir, NULL, create) != 0) || + (checkDirectory(normalizedmaildir, "tmp", create) != 0) || + (checkDirectory(normalizedmaildir, "cur", create) != 0) || + (checkDirectory(normalizedmaildir, "new", create) != 0)) { + returnValue = -1; + goto realend; + } + + messagesize = message->length; + + /* Step 1: chdir to maildir (and save current dir) */ + if (getcwd(olddirectory, PATHMAX) == NULL) { + returnValue = -1; + goto realend; + } + olddirectory[PATHMAX-1] = '\0'; + if(chdir(normalizedmaildir) != 0) { + returnValue = -1; + goto functionExit; + } + + /* Step 2: Stat the temporary file. Wait for ENOENT as a response. */ + for (count = 0;; count++) { + tmpname[0] = '\0'; + newname[0] = '\0'; + snprintf(basename, MAX_BASENAME, "%lu.%u_%lu.%s,S=%u", + time(NULL), getpid(), namecounter++, hostname, messagesize); + basename[MAX_BASENAME-1] = '\0'; + strcatn(tmpname, "tmp" DIRSEPSTR, MAX_SUBNAME); + strcatn(tmpname, basename, MAX_SUBNAME); + strcatn(newname, "new" DIRSEPSTR, MAX_SUBNAME); + strcatn(newname, basename, MAX_SUBNAME); + + if (stat(tmpname, &statbuf) == 0) + errno = EEXIST; + else if (errno == ENOENT) { + /* Step 4: create the file (at least try) */ + fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR); + if (fd >= 0) + break; /* we managed to open the file */ + } + + if (count > 5) { + /* Too many retries - give up */ + errlog(ERRORMSG, "Can't create message in %s\n", maildir); + returnValue = -1; + goto functionExit; + } + + /* Step 3: sleep and retry */ + sleep(2); + } + + /* Step 5: write file */ + if(write(fd, message->data, message->length) != message->length) { + returnValue = -1; + goto functionExit; + } + + /* on NFS this could fail */ +#ifndef WIN32 + if((fsync(fd) != 0) || (close(fd) != 0)) { +#else /* end of not WIN32 */ + if((_commit(fd) != 0) || (close(fd) != 0)) { +#endif /* else if WIN32 */ + returnValue = -1; + goto functionExit; + } + + /* Step 6: move message to 'cur' */ +#ifdef POSIX + for (count = 0;; count++) { + if(link(tmpname, newname) != 0) { + if (errno == EXDEV || errno == EPERM) { + /* We probably are on coda or some other filesystem that does not allow + * hardlinks. rename() the file instead of link() and unlink() + * I know, It's evil (PP). + */ + if (rename(tmpname, newname) != 0) { + returnValue = -1; + goto functionExit; + }; + break; + } else if (errno != EEXIST) { + returnValue = -1; + goto functionExit; + } + } else { + /* We successfully linked the message in new/. Now let's get + * rid of our tmp/ entry + */ + if(unlink(tmpname) != 0) { + /* unlinking failed */ + returnValue = -1; + goto functionExit; + } + break; + } + + if (count > 5) { + /* Too many retries - give up */ + errlog(ERRORMSG, "Can't move message to %s/new/\n", maildir); + returnValue = -1; + goto functionExit; + } + + sleep(2); + newname[0] = '\0'; + snprintf(basename, MAX_BASENAME, "%lu.%u_%lu.%s,S=%u", + time(NULL), getpid(), namecounter++, hostname, messagesize); + basename[MAX_BASENAME-1] = '\0'; + strcatn(newname, "new" DIRSEPSTR, MAX_SUBNAME); + strcatn(newname, basename, MAX_SUBNAME); + } +#else /* end of POSIX */ + /* On non POSIX systems we simply use rename(). Let's hope DJB + * never finds out + */ + if (rename(tmpname, newname) != 0) { + returnValue = -1; + goto functionExit; + }; +#endif /* else if not POSIX */ + + returnValue = 0; + +functionExit: + /* return to original directory */ + assert(olddirectory[0] != '\0'); + if(chdir(olddirectory) != 0) + returnValue = -1; + +realend: + + return returnValue; +} + +#else /* end of SHORTNAMES */ +int maildirWrite(char *maildir, BUFFER *message, int create) { +{ + errlog(ERRORMSG, "Maildir delivery does not work with SHORTNAMES.\n"); + return -1; +} +#endif /* else if not SHORTNAMES */ + + +#ifdef UNITTEST + +#ifdef NDEBUG +#undef NDEBUG +#endif /* NDEBUG */ + +#include <dirent.h> + +/* mock-up of errlog for unittest */ +void errlog(int type, char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +/* main for unittest */ +int main() +{ + int i, count = 23; + int fd; + DIR *d; + struct dirent *de; + BUFFER message; + char text[] = "From: nobody@un.bewaff.net\nTo: hackers@c0re.jp\nSubject: testing\n\nthis is just a test\n"; + char buf[1024]; + + /* create buffer with test data */ + message.data = text; + message.length = strlen(text); + + /* write <count> messages to maildir */ + for(i = 0; i < count; i++) + assert(maildirWrite("Maildir.test_maildir", message, 1) == 0); + + /* read them back */ + assert((d = opendir("Maildir.test_maildir/new")) != NULL); + for (i = 0; i < count + 2; i++) + { + de = readdir(d); + if(de->d_name[0] != '.') + { + buf[0] = '\0'; + strcat(buf, "Maildir.test_maildir/new/"); + strcat(buf, de->d_name); + fd = open(buf, O_RDONLY); + assert(unlink(buf) == 0); + assert(read(fd, buf, strlen(text)) == strlen(text)); + buf[strlen(text)] = '\0'; + /* check if they match the original message */ + assert(strcmp(text, buf) == 0); + close(fd); + } + } + + /* no files left in directory? */ + assert(readdir(d) == NULL); + + /* delete maildir */ + assert(rmdir("Maildir.test_maildir/tmp") == 0); + assert(rmdir("Maildir.test_maildir/new") == 0); + assert(rmdir("Maildir.test_maildir/cur") == 0); + assert(rmdir("Maildir.test_maildir") == 0); + + /* check if writing to a non existant maildir yilds an error */ + assert(maildirWrite("Maildir.test_maildir", &message, 0) == -1); + + puts("OK"); +} +#endif /* UNITTEST */ diff --git a/Src/main.c b/Src/main.c @@ -0,0 +1,820 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Command-line based frontend + $Id: main.c 937 2006-06-24 15:52:20Z colin $ */ + + +#include "mix3.h" +#include "pgp.h" +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#ifdef POSIX +#include <unistd.h> +#else /* end of POSIX */ +#include <io.h> +#endif /* else if not POSIX */ +#include <assert.h> + +static char *largopt(char *p, char *opt, char *name, int *error); +static void noarg(char *name, char p); +static int check_get_pass(int force, int never_ask_for_passphrase); + +/** main *****************************************************************/ + +/* Returns: + 0 successful operation + 1 command line error + 2 client error condition */ + +#ifdef WIN32SERVICE +int mix_main(int argc, char *argv[]) +#else +int main(int argc, char *argv[]) +#endif /* WIN32SERVICE */ +{ + int error = 0, deflt = 1, help = 0, readmail = 0, send = -1, sendpool = 0, + header = 1, maint = 0, keygen = 0, verbose = 0, sign = 0, encrypt = 0, + redirect_mail = 0, about=0, version=0; + int daemon = 0, type_list = 0, nodetach = 0; + int update_stats = 0, update_pingerlist = 0; + int never_ask_for_passphrase = 0; + +#ifdef USE_SOCK + int pop3 = 0; + +#endif /* USE_SOCK */ + char *filename = NULL; + int i; + int ret = 0; + char *p, *q; + char chain[1024] = ""; + char nym[LINELEN] = ""; + BUFFER *nymopt, *pseudonym, *attachments, *statssrc; + int numcopies = 0; /* default value set in mix.cfg */ + BUFFER *msg, *chainlist, *field, *content; + FILE *f; + char pingpath[PATHMAX]; + + /* Check if parse_yearmonthday works */ + assert(parse_yearmonthday("2003-04-01") == 1049155200); + + mix_init(NULL); + + msg = buf_new(); + chainlist = buf_new(); + nymopt = buf_new(); + pseudonym = buf_new(); + attachments = buf_new(); + field = buf_new(); + content = buf_new(); + statssrc = buf_new(); + +#ifdef USE_NCURSES + if (argc == 1) { + if (isatty(fileno(stdin))) + menu_main(); + else + menu_folder(0, NULL); + goto clientpool; + } +#endif /* USE_NCURSES */ + if (argc > 1 && strleft(argv[1], "-f")) { + menu_folder(strlen(argv[1]) > 2 ? argv[1][2] : 0, argc < 3 ? NULL : argv[2]); + goto clientpool; + } + for (i = 1; i < argc; i++) { + p = argv[i]; + if (p[0] == '-' && p[1] != '\0') { + if (p[1] == '-') { + p += 2; + if (strieq(p, "help")) + help = 1, deflt = 0; + else if (streq(p, "version")) + version = 1, deflt = 0; + else if (streq(p, "about")) + about = 1, deflt = 0; + else if (streq(p, "verbose")) + verbose = 1; + else if (streq(p, "type-list")) + type_list = 1; + else if (streq(p, "dummy")) + send = MSG_NULL, deflt = 0; + else if (streq(p, "remailer")) + maint = 1, deflt = 0; + else if (streq(p, "generate-key")) + keygen = 2, deflt = 0; + else if (streq(p, "update-keys")) + keygen = 1, deflt = 0; + else if (streq(p, "send")) + sendpool = 1, deflt = 0; + else if (streq(p, "read-mail")) + readmail = 1, deflt = 0; + else if (streq(p, "redirect")) + redirect_mail = 1, deflt = 0; + else if (streq(p, "store-mail")) + readmail = 2, deflt = 0; +#ifdef USE_SOCK + else if (streq(p, "pop-mail")) + pop3 = 1, deflt = 0; +#endif /* USE_SOCK */ + else if (streq(p, "daemon")) + daemon = 1, deflt = 0; + else if (streq(p, "no-detach")) + nodetach = 1; + else if (streq(p, "post")) + send = MSG_POST; + else if (streq(p, "mail")) + send = MSG_MAIL; + else if (streq(p, "sign")) + sign = 1; + else if (streq(p, "encrypt")) + encrypt = 1; + else if (streq(p, "no-ask-passphrase")) + never_ask_for_passphrase = 1; + else if (streq(p, "update-pinger-list")) + update_pingerlist = 1; + else if (streq(p, "update-stats")) { + buf_clear(statssrc); + f = mix_openfile(STATSSRC, "r"); + if (f != NULL) { + buf_read(statssrc, f); + fclose(f); + } + if (statssrc->length > 0) { + update_stats = 1; + } else { + deflt = 0; + fprintf(stderr, "%s: No current stats source --%s\n", argv[0], p); + } + } else if (strleft(p, "update-stats") && p[strlen("update-stats")] == '=') { + buf_clear(statssrc); + buf_appendf(statssrc, "%s", (p + strlen("update-stats") + 1)); + if (statssrc->length > 0) { + update_stats = 1; + } else { + fprintf(stderr, "%s: No stats source specified --%s\n", argv[0], p); + } + } else if ((q = largopt(p, "to", argv[0], &error)) != NULL) { + header = 0; + buf_appendf(msg, "To: %s\n", q); + } else if ((q = largopt(p, "post-to", argv[0], &error)) != NULL) { + send = MSG_POST, header = 0; + buf_appendf(msg, "Newsgroups: %s\n", q); + } else if ((q = largopt(p, "subject", argv[0], &error)) != NULL) { + buf_appendf(msg, "Subject: %s\n", q); + } else if ((q = largopt(p, "header", argv[0], &error)) != NULL) { + buf_appendf(msg, "%s\n", q); + } else if ((q = largopt(p, "chain", argv[0], &error)) != NULL) { + buf_appendf(msg, "Chain: %s\n", q); + } +#ifdef USE_PGP + else if ((q = largopt(p, "reply-chain", argv[0], &error)) != NULL) { + buf_appendf(msg, "Reply-Chain: %s\n", q); + } else if ((q = largopt(p, "latency", argv[0], &error)) != NULL) { + buf_appendf(msg, "Latency: %s\n", q); + } else if ((q = largopt(p, "attachment", argv[0], &error)) != NULL) { + buf_appendf(attachments, "%s\n", q); +#ifdef NYMSUPPORT + } else if ((q = largopt(p, "nym-config", argv[0], &error)) != NULL) { + deflt = 0; + strncpy(nym, q, sizeof(nym)); + if (i > argc && strileft(argv[i + 1], "name=")) + buf_sets(pseudonym, argv[++i] + 5); + else if (i > argc && strileft(argv[i + 1], "opt=")) + buf_appends(nymopt, argv[++i] + 5); + } else if ((q = largopt(p, "nym", argv[0], &error)) != NULL) { + buf_appendf(msg, "Nym: %s\n", q); +#endif /* NYMSUPPORT */ + } +#endif /* USE_PGP */ + else if ((q = largopt(p, "copies", argv[0], &error)) != NULL) { + sscanf(q, "%d", &numcopies); + } else if ((q = largopt(p, "config", argv[0], &error)) != NULL) { + strncpy(MIXCONF, q, PATHMAX); + MIXCONF[PATHMAX-1] = 0; + mix_config(); /* configuration file changed - reread it */ + } else if (error == 0 && mix_configline(p) == 0) { + fprintf(stderr, "%s: Invalid option %s\n", argv[0], argv[i]); + error = 1; + } + } else { + while (*++p) { + switch (*p) { + case 'd': + send = MSG_NULL, deflt = 0; + break; + case 'R': + readmail = 1, deflt = 0; + break; + case 'I': + readmail = 2, deflt = 0; + break; + case 'S': + sendpool = 1, deflt = 0; + break; + case 'M': + maint = 1, deflt = 0; + break; +#ifdef USE_SOCK + case 'P': + pop3 = 1, deflt = 0; + break; +#endif /* USE_SOCK */ + case 'D': + daemon = 1, deflt = 0; + break; + case 'G': + keygen = 2, deflt = 0; + break; + case 'K': + keygen = 1, deflt = 0; + break; + case 'L': /* backwards compatibility */ + break; + case 'v': + verbose = 1; + break; + case 'h': + help = 1, deflt = 0; + break; + case 'T': + type_list = 1; + break; + case 'V': + version = 1, deflt = 0; + break; + case 't': + if (*(p + 1) == 'o') + p++; + header = 0; + if (i < argc - 1) + buf_appendf(msg, "To: %s\n", argv[++i]); + else { + fprintf(stderr, "%s: Missing argument for option -to\n", argv[0]); + error = 1; + } + break; + case 's': + if (i < argc - 1) + buf_appendf(msg, "Subject: %s\n", argv[++i]); + else { + noarg(argv[0], *p); + error = 1; + } + break; + case 'l': + if (i < argc - 1) + buf_appendf(msg, "Chain: %s\n", argv[++i]); + else { + noarg(argv[0], *p); + error = 1; + } + break; + case 'r': + if (i < argc - 1) + buf_appendf(msg, "Reply-Chain: %s\n", argv[++i]); + else { + noarg(argv[0], *p); + error = 1; + } + break; +#ifdef USE_PGP + case 'n': + if (i < argc - 1) + buf_appendf(msg, "Nym: %s\n", argv[++i]); + else { + noarg(argv[0], *p); + error = 1; + } + break; +#endif /* USE_PGP */ + case 'c': + if (i < argc - 1) + sscanf(argv[++i], "%d", &numcopies); + else { + noarg(argv[0], *p); + error = 1; + } + break; + case 'p': + send = MSG_POST; + break; + case 'g': + if (i < argc - 1) { + send = MSG_POST, header = 0; + buf_appendf(msg, "Newsgroups: %s\n", argv[++i]); + } else { + noarg(argv[0], *p); + error = 1; + } + break; + case 'a': + if (i < argc - 1) + buf_appendf(attachments, "%s\n", argv[++i]); + else { + noarg(argv[0], *p); + error = 1; + } + break; + case 'm': + send = MSG_MAIL; + break; + default: + fprintf(stderr, "%s: Invalid option -%c\n", argv[0], *p); + error = 1; + break; + } + } + } + } else { + if (strchr(argv[i], '@')) { + header = 0; + buf_appendf(msg, "To: %s\n", argv[i]); + } else { + if (filename == NULL) + filename = argv[i]; + else { + fprintf(stderr, "%s: Error in command line: %s\n", argv[0], argv[i]); + error = 1; + } + } + } + } + + if (error) { + ret = 1; + goto end; + } + + if (type_list) { + BUFFER *type2list; + type2list = buf_new(); + if (prepare_type2list(type2list) < 0) { + fprintf(stderr, "Cannot print type2.list.\n"); + ret = 2; + } else { + printf("%s", type2list->data); + }; + buf_free(type2list); + goto end; + } + + if (version) { + printf("Mixmaster %s\n", VERSION); + ret = 0; + goto end; + } + + if (update_pingerlist) { + mixfile(pingpath, ALLPINGERSFILE); + if (verbose) printf ("downloading %s...\n", ALLPINGERSURL); + if (url_download(ALLPINGERSURL, pingpath) < 0) { + printf(" Download failed... Try again later.\n"); + errlog(ERRORMSG, "All Pingers File Download failed.\n"); + } else { + if (verbose) printf(" Done.\n"); + errlog(LOG, "All Pingers File Downloaded OK.\n"); + } + ret = 0; + goto end; + } + + if (update_stats) { + ret = download_stats(statssrc->data); + if (ret == -3) { + fprintf(stderr, "Stats source does not include all required files.\n"); + } else if (ret == -2) { + fprintf(stderr, "Could not open stats source file for writing\n"); + } else if (ret == -1) { + fprintf(stderr, "Stats source download failed.\n"); + } + ret = 0; + goto end; + } + +#ifdef USE_NCURSES +/* If we get here then it's possible we still want to use the NCURSES interface */ + if (deflt && (send == -1) && isatty(fileno(stdin))) { + menu_main(); + goto clientpool; + } +#endif /* USE_NCURSES */ + + if (help ||about ||(isatty(fileno(stdin)) && isatty(fileno(stdout)))) + fprintf(stderr, "Mixmaster %s\n", VERSION); + if (help ||about) + printf("\n\n"); + if (about) { + printf("Many people have contributed to the source code for Mixmaster.\n"); + printf("These contributors include:\n\n"); + printf("Lance Cottrell\n"); + printf("Janis Jagars\n"); + printf("Ulf Moeller\n"); + printf("Peter Palfrader\n"); + printf("Len Sassaman\n"); + printf("\nand others. For full information on copyright and license issues,\n"); + printf("read the bundled file COPYRIGHT.\n\n"); + ret = 0; + goto end; + } + + if (help) { + printf("Usage: %s [options] [user@host] [filename]\n\n", argv[0]); + printf("Options:\n\ +\n\ +-h, --help summary of command line options\n\ +-V, --version print version information\n\ + --about print authorship information\n\ +-T, --type-list list available remailers\n\ +-t, --to=user@host the recipient's address(es)\n\ +-g, --post-to=newsgroup newsgroup(s) to post to\n\ +-p, --post input is a Usenet article\n\ +-m, --mail input is a mail message\n\ +-s, --subject=subject message subject\n\ + --header='header line' arbitrary message headers\n\ +-a, --attachment=file attach a file\n" +#ifdef USE_PGP +#ifdef NYMSUPPORT + "-n, --nym=yournym use pseudonym to send the message\n" +#endif /* NYMSUPPORT */ +" --encrypt encrypt the message using the PGP format\n\ + --sign sign the message using the PGP format\n" +#endif /* USE_PGP */ + "-l, --chain=mix1,mix2,mix3,... specify a remailer chain\n\ +-c, --copies=num send num copies to increase reliability\n\ +-d, --dummy generate a dummy message\n\ +-S, --send send the message(s) in the pool\n" +#ifdef USE_PGP +#ifdef NYMSUPPORT + " --nym-config=yournym generate a new pseudonym\n\ + --latency=hours reply chain latency\n\ + --reply-chain=rem1,rem2,... reply chain for the pseudonym\n" +#endif /* NYMSUPPORT */ +#endif /* USE_PGP */ + "-v, --verbose output informational messages\n\ +-f [file] read a mail folder\n\ + --update-pinger-list Download an updated all pingers list file\n\ + --update-stats[=source] Download updated stats\n" + +#ifndef USE_NCURSES + "\n-fr, -ff, -fg [file] send reply/followup/group reply to a message\n" +#endif /* USE_NCURSES */ + "\nThe input file is expected to contain mail headers if no address is\n\ +specified in the command line.\n\ +\n\ +Remailer:\n\ +\n\ +-R, --read-mail read remailer message from stdin\n\ +-I, --store-mail read remailer msg from stdin, do not decrypt\n\ +-M, --remailer process the remailer pool\n\ +-D, --daemon remailer as background process\n\ + --no-detach do not detach from terminal as daemon\n" +#ifdef USE_SOCK + "-S, --send force sending messages from the pool\n" +#endif /* USE_SOCK */ + "-P, --pop-mail force getting messages from POP3 servers\n\ +-G, --generate-key generate a new remailer key\n\ +-K, --update-keys generate remailer keys if necessary\n\ + --config=file use alternate configuration file\n" +#ifdef WIN32SERVICE + "\n\ +WinNT service:\n\ +\n\ + --install-svc install the service\n\ + --remove-svc remove the service\n\ + --run-svc run as a service\n" +#endif /* WIN32SERVICE */ + ); + + ret = 0; + goto end; + } + + if (deflt && send == -1) + send = MSG_MAIL; + if (nym[0] != 0) + send = -1; + if ((send == MSG_MAIL || send == MSG_POST) && filename == NULL && + header == 1 && isatty(fileno(stdin))) { + /* we don't get here if USE_NCURSES is set */ + printf("Run `%s -h' to view a summary of the command line options.\n\nEnter the message, complete with headers.\n", + argv[0]); +#ifdef UNIX + printf("When done, press ^D.\n\n"); +#else + printf("When done, press ^Z.\n\n"); +#endif /* else not UNIX */ + } + if (header == 0) + buf_nl(msg); + + /* timeskew check */ + if (REMAIL == 1) + mix_check_timeskew(); + + if (readmail || redirect_mail || send == MSG_MAIL || send == MSG_POST) { + if (filename == NULL || streq(filename, "-")) + f = stdin; + else { + f = fopen(filename, "r"); + if (f == NULL) + fprintf(stderr, "Can't open %s.\n", filename); + } + + if (f && buf_read(msg, f) != -1) { + if (readmail == 1) { + check_get_pass(1, never_ask_for_passphrase); + mix_decrypt(msg); + } else if (readmail == 2) + pool_add(msg, "inf"); + if (send == MSG_MAIL || send == MSG_POST || redirect_mail) { + BUFFER *sendmsg; + int numdest = 0; + + sendmsg = buf_new(); + + while (buf_getheader(msg, field, content) == 0) { + if (bufieq(field, "nym")) { + strncpy(nym, content->data, sizeof(nym)); + } else if (bufieq(field, "chain")) + if (strchr(content->data, ';')) { + i = strchr(content->data, ';') - (char *)content->data; + strncpy(chain, content->data, i); + if (strstr(content->data + i, "copies=") != NULL) { + sscanf(strstr(content->data + i, "copies=") + + sizeof("copies=") - 1, "%d", &numcopies); + } + } else + strncpy(chain, content->data, sizeof(chain)); + else { /* line goes into message */ + if (((redirect_mail || send == MSG_MAIL) && bufieq(field, "to")) + || (send == MSG_POST && bufieq(field, "newsgroups"))) + numdest++; + if (bufieq(field, "from") && !redirect_mail) + fprintf(stderr, "Warning: The message has a From: line.\n"); + buf_appendheader(sendmsg, field, content); + } + } + buf_nl(sendmsg); + buf_rest(sendmsg, msg); + + while (buf_getline(attachments, field) != -1) + if (attachfile(sendmsg, field) == -1) { + errlog(ERRORMSG, "Can't attach %b!\n", field); + ret = 2; + goto end; + } + +#ifdef USE_PGP + if (nym[0] != 0 && strchr(nym, '@') == NULL) + strcatn(nym, "@", sizeof(nym)); + if (sign || encrypt) { + BUFFER *pass; + + pass = buf_new(); + user_pass(pass); + if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0) | + (nym[0] != 0 && sign ? PGP_SIGN : 0) | + PGP_TEXT | PGP_REMAIL, sendmsg, nym, + pass, NULL, NYMSECRING) != 0) { + fprintf(stderr, "Encryption failed: missing key!"); + ret = 2; + goto end; + } + buf_free(pass); + } + if (nym[0] != 0) { +#ifdef NYMSUPPORT + if (nym_encrypt(sendmsg, nym, send) == 0) + send = MSG_MAIL; + else +#endif /* NYMSUPPORT */ + fprintf(stderr, "Nym error, sending message anonymously.\n"); + } +#endif /* USE_PGP */ + if (numdest == 0) { + fprintf(stderr, "No destination address given!\n"); + ret = 2; + } else if (numcopies < 0 || numcopies > 10) { + fprintf(stderr, "Invalid number of copies!\n"); + ret = 2; + } else { + if ( ( redirect_mail ? + redirect_message(sendmsg, chain, numcopies, chainlist) : + mix_encrypt(send, sendmsg, chain, numcopies, chainlist) + ) == -1) { + ret = 2; + if (chainlist->length) + fprintf(stderr, "%s\n", chainlist->data); + else + fprintf(stderr, "Failed!\n"); + } else if (verbose) { + fprintf(stderr, "Chain: "); + buf_write(chainlist, stderr); + } + } + + buf_free(sendmsg); + } + if (filename != NULL) + fclose(f); + } else + ret = 2; + } + if (send == MSG_NULL) { + if (msg->length) { + while (buf_getheader(msg, field, content) == 0) { + if (bufieq(field, "chain")) + strncpy(chain, content->data, sizeof(chain)); + } + } + if (mix_encrypt(MSG_NULL, NULL, chain, numcopies, chainlist) == -1) { + ret = 2; + if (chainlist->length) + printf("%s\n", chainlist->data); + else + fprintf(stderr, "Failed!\n"); + } else if (verbose) { + printf("Chain: "); + buf_write(chainlist, stdout); + } + } +#ifdef USE_PGP +#ifdef NYMSUPPORT + if (nym[0] != 0) { + char nymserver[LINELEN] = "*"; + BUFFER *chains; + + chains = buf_new(); + if (numcopies < 1 || numcopies > 10) + numcopies = 1; + while (buf_getheader(msg, field, content) != -1) { + if (bufieq(field, "chain")) + strncpy(chain, content->data, sizeof(chain)); + else if (bufieq(field, "reply-chain")) + buf_appendf(chains, "Chain: %b\n", content); + else if (field->length) + buf_appendheader(chains, field, content); + else + buf_nl(chains); + } + if (strrchr(nym, '@')) { + strncpy(nymserver, strrchr(nym, '@'), sizeof(nymserver)); + *strrchr(nym, '@') = '\0'; + } + if (nym_config(NYM_CREATE, nym, nymserver, pseudonym, + chain, numcopies, chains, nymopt) < 0) { + ret = 2; + fprintf(stderr, "Failed!\n"); + } + user_delpass(); + buf_free(chains); + } +#endif /* NYMSUPPORT */ +#endif /* USE_PGP */ + + if (keygen) { + check_get_pass(0, never_ask_for_passphrase); + keymgt(keygen); + } + if (sendpool) + mix_send(); +#ifdef USE_SOCK + if (pop3) + pop3get(); +#endif /* USE_SOCK */ + if (maint) { + check_get_pass(1, never_ask_for_passphrase); + mix_regular(0); + } + +clientpool: + if ((REMAIL == 0) && (CLIENTAUTOFLUSH == 1)) { + SENDPOOLTIME = 0; + RATE = 100; + mix_send(); + }; + +end: + buf_free(field); + buf_free(content); + buf_free(chainlist); + buf_free(msg); + buf_free(nymopt); + buf_free(pseudonym); + buf_free(attachments); + buf_free(statssrc); + + if (daemon) { + check_get_pass(1, never_ask_for_passphrase); +#ifdef UNIX + if (! nodetach) { + int pid; + + fprintf(stderr, "Detaching.\n"); + /* Detach as suggested by the Unix Programming FAQ */ + pid = fork(); + if (pid > 0) + exit(0); + if (setsid() < 0) { + /* This should never happen. */ + fprintf(stderr, "setsid() failed.\n"); + exit(1); + }; + pid = fork(); + if (pid > 0) + exit(0); + }; + if (chdir(MIXDIR) < 0) { + if (chdir("/") < 0) { + fprintf(stderr, "Cannot chdir to mixdir or /.\n"); + exit(1); + }; + }; + if (write_pidfile(PIDFILE)) { + fprintf(stderr, "Aborting.\n"); + exit(1); + } + if (! nodetach) { + freopen ("/dev/null", "r", stdin); + freopen ("/dev/null", "w", stdout); + freopen ("/dev/null", "w", stderr); + } +#endif /* UNIX */ + mix_daemon(); +#ifdef UNIX +/* ifdef this one too, so that we do not need to export it from windows dll */ + clear_pidfile(PIDFILE); +#endif /* UNIX */ + } + mix_exit(); + return (ret); +} + +static char *largopt(char *p, char *opt, char *name, int *error) +{ + if (streq(p, opt)) { + fprintf(stderr, "%s: Missing argument for option --%s\n", name, p); + *error = 1; + } else if (strleft(p, opt) && p[strlen(opt)] == '=') { + return (p + strlen(opt) + 1); + } + return (NULL); +} + +static void noarg(char *name, char p) +{ + fprintf(stderr, "%s: Missing argument for option -%c\n", name, p); +} + +static int check_get_pass(int force, int never_ask_for_passphrase) +/* get a passphrase and check against keys + * if force != 0 passphrase must match with some key */ +{ + BUFFER *pass, *pass2, *key; + int n = 0; + + if (PASSPHRASE[0] == '\0' && isatty(fileno(stdin)) && ! never_ask_for_passphrase) { + pass = buf_new(); + pass2 = buf_new(); + key = buf_new(); + buf_sets(pass, PASSPHRASE); + while ( +#ifdef USE_PGP + pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, pass) < 0 && + pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, pass) < 0 && +#endif /* USE_PGP */ + getv2seckey(NULL, key) < 0) + { + user_delpass(); + if (n) + fprintf(stderr, "re-"); + user_pass(pass); + strncpy(PASSPHRASE, pass->data, LINELEN); + PASSPHRASE[LINELEN-1] = 0; + if (!force) { + if (n && buf_eq(pass, pass2)) + break; + buf_set(pass2, pass); + } + n=1; + } + user_delpass(); + buf_free(pass); + buf_free(pass2); + buf_free(key); + + strncpy(ENTEREDPASSPHRASE, PASSPHRASE, LINELEN); + ENTEREDPASSPHRASE[LINELEN-1] = 0; + } + return 1; +} diff --git a/Src/menu.c b/Src/menu.c @@ -0,0 +1,1003 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Menu-based user interface + $Id: menu.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "menu.h" +#include "mix3.h" +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <fcntl.h> +#ifdef POSIX +#include <unistd.h> +#else /* end of POSIX */ +#include <io.h> +#endif /* else if not POSIX */ +#include <assert.h> + +void menu_folder(char command, char *foldername) +{ + mix_init(NULL); + if (foldername) + menu_init(); + read_folder(command, foldername, ANON); + menu_exit(); +} + +void read_folder(char command, char *foldername, char *nym) +{ +#ifdef USE_NCURSES + char path[PATHMAX] = "stdin", path_with_tilde[PATHMAX], l[LINELEN]; +#else /* end of USE_NCURSES */ + char path[PATHMAX] = "stdin", l[LINELEN]; +#endif /* else if not USE_NCURSES */ + char *h; + FILE *f; + BUFFER *folder; + BUFFER *line, *field, *content, *name; + BUFFER *index; + BUFFER *mail, *log; + int mailfolder = -1; /* -1 = unknown, 0 = no mailfolder, 1 = mailfolder */ + int num = 0; + long from = -1, subject = -1; + int folder_has_changed; +#ifdef USE_NCURSES + BUFFER *deleted_message; + BUFFER *new_folder; + BUFFER *new_index; + long length; + char sub[LINELEN], str[LINELEN], search[LINELEN] = ""; + long p; + int display, range, selected, i, redraw, c, q; + +#endif /* USE_NCURSES */ + int ispgp = 0, eof = 0; + folder_has_changed = 0; + + line = buf_new(); + field = buf_new(); + content = buf_new(); + index = buf_new(); + mail = buf_new(); + name = buf_new(); + folder = buf_new(); + log = buf_new(); + + if (foldername == NULL) + f = stdin; + else { + if (foldername[0] == '~' && (h = getenv("HOME")) != NULL) { + strncpy(path, h, PATHMAX); + strcatn(path, foldername + 1, PATHMAX); + } else + strncpy(path, foldername, PATHMAX); + f = fopen(path, "r"); + } + if (f == NULL) { +#ifdef USE_NCURSES + if (foldername) + beep(); +#endif /* USE_NCURSES */ + mix_status("Can't read %s.\n", path); + goto end; + } + for (;;) { + if (fgets(l, sizeof(l), f) == NULL) + eof = 1; + else if (mailfolder == -1) { + if (strleft(l, "From ")) + mailfolder = 1; + else if (strileft(l, "from:") || strileft(l, "path:") + || strileft(l, "xref:") || strileft(l, "return-path")) + mailfolder = 0; + else + break; + } + if (eof || (mailfolder && strleft(l, "From ")) || + (mailfolder == 0 && from != -1 && + (strileft(l, "path:") || + strileft(l, "xref:") || strileft(l,"return-path")))) { + if (num > 1) + mix_status("Reading message %d", num); +#ifdef USE_PGP + if (ispgp) +#ifdef NYMSUPPORT + switch (nym_decrypt(mail, NULL, log)) { + case 2: + from = -1, subject = -1; + while (buf_getline(mail, line) == 0) { + if (bufileft(line, "from:")) + from = folder->length + mail->ptr - line->length - 1; + if (bufileft(line, "subject:")) + subject = folder->length + mail->ptr - line->length - 1; + } + folder_has_changed = 1; + break; + case -1: + buf_clear(mail); + from = -1, subject = -1; + continue; + default: + ; + } +#else + if (!eof) { + buf_clear(mail); + from = -1, subject = -1; + continue; + } +#endif /* NYMSUPPORT */ +#endif /* USE_PGP */ + buf_cat(folder, mail); + buf_clear(mail); + ispgp = 0; + if (num > 0) { + buf_appendl(index, from); + buf_appendl(index, subject); + } + if (eof) + break; + + buf_appendl(index, folder->length); + from = subject = -1; + num++; + } + if (from == -1 && strileft(l, "from:")) + from = folder->length + mail->length; + + if (subject == -1 && strileft(l, "subject:")) + subject = folder->length + mail->length; + + buf_appends(mail, l); + if (strleft(l, begin_pgp)) + ispgp = 1; + } + + if (foldername) + fclose(f); + else { + dup2(open("/dev/tty", O_RDWR), fileno(stdin)); + menu_init(); + } + + mix_status(""); + if (folder->length == 0) { +#ifdef USE_NCURSES + clear(); + beep(); +#endif /* USE_NCURSES */ + mix_status("%s is empty.\n", path); + goto end; + } + if (mailfolder == -1) { +#ifdef USE_NCURSES + clear(); + beep(); +#endif /* USE_NCURSES */ + mix_status("%s is not a mail folder.\n", path); + goto end; + } +#ifndef USE_NCURSES + if (command == 0) { + buf_write(folder, stdout); + goto end; + } + if (num > 1) { + mix_status("Folder contains several messages."); + goto end; + } +#endif /* not USE_NCURSES */ + + if (num < 2) { + folder->ptr = 0; + mimedecode(folder); + + if (command != 0) + send_message(command, nym, folder); +#ifdef USE_NCURSES + else + read_message(folder, nym); + + clear(); +#endif /* USE_NCURSES */ + goto end; + } +#ifdef USE_NCURSES + display = selected = 0; + range = LINES - 3; + redraw = 2; + + for (;;) { + if (selected < 0) + selected = 0; + if (selected >= num) + selected = num - 1; + + if (selected < display) { + display = selected - range / 2; + redraw = 2; + } + if (selected >= display + range) { + display = selected - range / 2; + redraw = 2; + } + if (display >= num - 5) + display = num - 5; + if (display < 0) + display = 0; + + if (redraw) { + if (redraw == 2) { + clear(); + standout(); + mvprintw(0, 0, "Mixmaster %s", VERSION); + printw(" %.20s reading %.50s", nym, path); + standend(); + } + for (i = display; i < display + range; i++) { + if (i < num) { + index->ptr = 12 * i; + p = buf_getl(index); + buf_clear(name); + folder->ptr = buf_getl(index); + if (folder->ptr < 0) + folder->ptr = 0; + else { + buf_getheader(folder, field, line); + if (line->length) { + decode_header(line); + rfc822_name(line, name); + } + } + if (i == selected) + standout(); + + mvaddnstr(i - display + 2, 0, name->data, 18); + + sub[0] = '\0'; + folder->ptr = buf_getl(index); + if (folder->ptr < 0) + folder->ptr = 0; + else { + buf_getheader(folder, field, content); + if (content->length) { + decode_header(content); + strncpy(sub, content->data, sizeof(sub)); + } + } + if (sub[0] == '\0') + strcpy(sub, "(no subject)"); + mvaddnstr(i - display + 2, 20, sub, COLS - 21); + + if (i == selected) + standend(); + } + } + } + move(LINES - 1, COLS - 1); + refresh(); + redraw = 0; + + c = getch(); + switch (c) { + case '\014': + display = selected - range / 2; + redraw = 2; + break; + case 'q': + clear(); + goto end; + case '/': + echo(); + cl(LINES - 1, 0); + printw("Search: "); + refresh(); + wgetnstr(stdscr, str, LINELEN); + if (str[0] != '\0') + strncpy(search, str, LINELEN); + noecho(); + for (i = (selected < num ? selected + 1 : 0); i < num; i++) { + index->ptr = 12 * i + 4; + folder->ptr = buf_getl(index); + if (folder->ptr < 0) + folder->ptr = 0; + else { + buf_getheader(folder, field, line); + if (line->length) { + decode_header(line); + if (bufifind(line, search)) + break; + } + } + folder->ptr = buf_getl(index); + if (folder->ptr < 0) + folder->ptr = 0; + else { + buf_getheader(folder, field, line); + if (line->length) { + decode_header(line); + if (bufifind(line, search)) + break; + } + } + } + if (i < num) + selected = i; + else + beep(); + redraw = 1; + break; + case '\r': /* read message */ + case '\n': + case 'r': /* reply to message */ + case 'g': + case 'f': + case 'm': + case 'p': + case 's': + index->ptr = 12 * selected; + p = buf_getl(index); + if (selected < num - 1) { + index->ptr = 12 * (selected + 1); + q = buf_getl(index) - p; + } else + q = folder->length - p; + buf_clear(mail); + buf_append(mail, folder->data + p, q); + mimedecode(mail); + if(c == 's') + savemsg(mail); + else{ + if (c == '\r' || c == '\n') + read_message(mail, nym); + else + send_message(c, nym, mail); + } + redraw = 2; + break; + case 'd': /* delete message */ + /* Remove message from folder */ + if(num > 0){ + index->ptr = 12 * selected; + p = buf_getl(index); + if (selected < num - 1) { + index->ptr = 12 * (selected + 1); + q = buf_getl(index) - p; + } else + q = folder->length - p; + deleted_message = buf_new(); + new_folder = buf_new(); + buf_cut_out(folder, deleted_message, new_folder, p, q); + buf_free(deleted_message); + buf_free(folder); + folder = new_folder; + /* Update index file */ + new_index = buf_new(); + index->ptr = 0; + if(selected > 0) + buf_get(index, new_index, 12 * selected); + index->ptr = 12 * (selected + 1); + while((from = buf_getl(index)) != -1){ + subject = buf_getl(index); + length = buf_getl(index); + buf_appendl(new_index, from - q); + buf_appendl(new_index, subject - q); + buf_appendl(new_index, length - q); + } + buf_free(index); + index = new_index; + /* Done */ + num--; + folder_has_changed = 1; + } + redraw = 2; + break; + case KEY_UP: + selected--; + redraw = 1; + break; + case KEY_DOWN: + case 'n': /* nym ???? */ + selected++; + redraw = 1; + break; + case KEY_PPAGE: + selected -= range; + redraw = 1; + break; + case KEY_NPAGE: + selected += range; + redraw = 1; + break; + default: + beep(); + } + } +#endif /* USE_NCURSES */ + +end: +#ifdef USE_NCURSES + /* If folder has changed, ask user about saving new folder. */ + if (folder_has_changed && !streq(path, "stdin")) { + mvprintw(LINES - 2, 0, "Buffer has changed. Save [y/n]? "); + c = getch(); + cl(LINES - 2, 0); + if ((c == 'y') || (c == 'Y')){ + strncpy(path_with_tilde, path, PATHMAX-1); + strcat(path_with_tilde, "~"); + rename(path, path_with_tilde); /* Rename folder to folder~ */ + f = fopen(path, "w"); /* Write new folder */ + if (f == NULL) + mix_status("Can't write to %s.", path); + else{ + buf_write(folder, f); + mix_status("Wrote %s.", path); + fclose(f); + } + } + else{ + mix_status("%s was not saved.", path); + } + } +#endif /* USE_NCURSES */ + buf_free(folder); + buf_free(line); + buf_free(field); + buf_free(content); + buf_free(index); + buf_free(mail); + buf_free(name); + buf_free(log); +} + +#ifdef USE_NCURSES +static int sortrel(const void *a, const void *b) +{ + int na, ra, nb, rb; + + na = *(int *) a; + nb = *(int *) b; + + ra = *((int *) a + 1); + rb = *((int *) b + 1); + return rb - ra; +} + +void menu_main(void) +{ + int y, x; + int pool, n; + int c; + int space; + BUFFER *chainlist, *line; + char nym[LINELEN] = ANON; + + chainlist = buf_new(); + line = buf_new(); + + mix_init(NULL); + menu_init(); + +menu_redraw: + clear(); + for (;;) { + standout(); + mvprintw(0, 0, "Mixmaster %s", VERSION); +#if 0 + mvprintw(0, COLS - sizeof(COPYRIGHT), COPYRIGHT); +#endif + for (space = 0; space < (COLS - 10 - sizeof(VERSION)); space++) { + printw(" "); + }; + standend(); + mix_status(NULL); + +#ifdef NYMSUPPORT + mvprintw(8, 4, "n)ym: %s", nym); +#endif /* NYMSUPPORT */ + y = 12, x = 25; + mvprintw(y++, x, "m)ail"); + mvprintw(y++, x, "p)ost to Usenet"); + mvprintw(y++, x, "r)ead mail (or news article)"); + mvprintw(y++, x, "d)ummy message"); + mvprintw(y++, x, "s)end messages from pool"); + mvprintw(y++, x, "e)dit configuration file"); + mvprintw(y++, x, "u)pdate stats"); + mvprintw(y++, x, "q)uit"); + + pool = pool_read(NULL); + if (pool == 1) + mvprintw(4, 2, "%3d outgoing message in the pool. \n", pool); + else + mvprintw(4, 2, "%3d outgoing messages in the pool.\n", pool); + + move(LINES - 1, COLS - 1); + refresh(); + c = getch(); + if (c != ERR) { + mix_status(""); + switch (c) { + case '\014': + mix_status(""); + goto menu_redraw; +#ifdef NYMSUPPORT + case 'n': + menu_nym(nym); + goto menu_redraw; +#endif /* NYMSUPPORT */ + case 'm': + case 'p': + send_message(c, nym, NULL); + break; + case 'd': + mix_status("Creating message..."); + if (mix_encrypt(MSG_NULL, NULL, NULL, 1, chainlist) != 0) { + if (chainlist->length > 0) + mix_status("%s", chainlist->data); + else + mix_genericerror(); + beep(); + } else { + for (n = 0; buf_getline(chainlist, line) == 0; n++) ; + if (n > 1) + mix_status("Done (%d packets).", n); + else + mix_status("Chain: %s", chainlist->data); + } + break; + case 's': + mix_status("Mailing messages..."); + mix_send(); + mix_status("Done."); + break; + case 'r': + { + char name[LINELEN]; + + cl(LINES - 3, 0); + if (getenv("MAIL")) + printw("File name [%s]: ", getenv("MAIL")); + else + printw("File name: "); + echo(); + wgetnstr(stdscr, name, LINELEN); + noecho(); + cl(LINES - 3, 0); + if (name[0] == '\0') { + if (getenv("MAIL")) + read_folder(0, getenv("MAIL"), nym); + } else + read_folder(0, name, nym); + } + break; + case 'e': + do { + char path[PATHMAX]; + mixfile(path, MIXCONF); + menu_spawn_editor(path, 0); + mix_config(); + } while (0); + break; + case 'u': + update_stats(); + break; + case 'q': + case 'Q': + goto quit; + default: + beep(); + } + } + } + +quit: + menu_exit(); + buf_free(chainlist); + buf_free(line); +} + +void read_message(BUFFER *message, char *nym) +{ + int l = 0; + int c; + int inhdr = 1, txtbegin; + BUFFER *field, *content, *line, *hdr; + char sub[LINELEN] = "mail"; + char thisnym[LINELEN] = ""; + + field = buf_new(); + content = buf_new(); + line = buf_new(); + hdr = buf_new(); + + if (thisnym[0] == '\0') + strncpy(thisnym, nym, LINELEN); + + if (bufleft(message, "From nymserver ")) { + /* select nym if Nym: pseudo header is in the first line */ + buf_getline(message, line); + buf_getheader(message, field, content); + if (bufieq(field, "Nym")) + strncpy(thisnym, content->data, sizeof(thisnym)); + buf_rewind(message); + } + while (buf_getheader(message, field, content) == 0) { + if (bufieq(field, "received") || bufleft(field, "From ")) + continue; + if (bufieq(field, "subject")) + strncpy(sub, content->data, sizeof(sub)); + buf_appendheader(hdr, field, content); + } + if (strlen(sub) > COLS - strlen(VERSION) - strlen(thisnym) - 23) + sub[COLS - strlen(VERSION) - strlen(thisnym) - 24] = '\0'; + txtbegin = message->ptr; + +loop: + clear(); + standout(); + mvprintw(0, 0, "Mixmaster %s", VERSION); + printw(" %.20s reading %.50s\n", thisnym, sub); + standend(); + mix_status(NULL); + + while (l < LINES - 2) { + if (inhdr) { + if (buf_getline(hdr, line) == -1) + buf_clear(line), inhdr = 0; + } else { + if (buf_getline(message, line) == -1) { + standout(); + mvprintw(LINES - 1, 0, "Command"); + standend(); + refresh(); + for (;;) { + c = getch(); + switch (c) { + case 'm': + case 'p': + case 'r': + case 'g': + case 'f': + send_message(c, thisnym, message); + goto end; + case 'u': + inhdr = 0; + message->ptr = txtbegin; + l = 0; + goto loop; + case 'h': + inhdr = 1; + hdr->ptr = 0; + message->ptr = txtbegin; + l = 0; + goto loop; + case 's': + savemsg(message); + /* fallthru */ + case 'q': + case 'i': + case '\n': + case '\r': + goto end; + case '\014': + refresh(); + continue; + default: + beep(); + refresh(); + } + } + } + } + mvprintw(l + 1, 0, "%s\n", line->data); + l += (line->length - 1) / COLS + 1; + } + standout(); + mvprintw(LINES - 1, 0, "MORE"); + standend(); + refresh(); + for (;;) { + c = getch(); + switch (c) { + case 'm': + case 'p': + case 'r': + case 'g': + case 'f': + send_message(c, thisnym, message); + goto end; + case 'u': + inhdr = 0; + message->ptr = txtbegin; + l = 0; + goto loop; + case 'h': + inhdr = 1; /* show full header */ + hdr->ptr = 0; + message->ptr = txtbegin; + l = 0; + goto loop; + case 's': + savemsg(message); + /* fallthru */ + case 'q': + case 'i': + goto end; + case ' ': + case '\n': + case '\r': + l = 0; + goto loop; + case '\014': + refresh(); + continue; + default: + beep(); + refresh(); + } + } +end: + buf_free(field); + buf_free(content); + buf_free(line); + buf_free(hdr); +} + +int menu_replychain(int *d, int *l, char *mdest, char *pdest, char *psub, + char *r) +{ + int c; + char line[LINELEN]; + char reliability[9]; + +redraw: + clear(); + standout(); + printw("Create a nym reply block:"); + standend(); + mix_status(NULL); + + mvprintw(3, 0, "Type of reply block:\n"); + if (*d == MSG_MAIL) + standout(); + printw(" m)ail "); + if (*d == MSG_MAIL) + standend(); + + if (*d == MSG_POST) + standout(); + printw(" Usenet message p)ool "); + if (*d == MSG_POST) + standend(); + + if (*d == MSG_NULL) + standout(); + printw(" cover t)raffic "); + if (*d == MSG_NULL) + standend(); + + if (*d != MSG_NULL) + mvprintw(6, 0, "d)estination: %s", *d == MSG_MAIL ? mdest : pdest); + if (psub && *d == MSG_POST) + mvprintw(7, 0, "s)ubject: %s", psub); + chain_reliability(r, 1, reliability); /* chaintype 1=ek */ + mvprintw(8, 0, "c)hain: %-39s (reliability: %s)", r, reliability); + mvprintw(10, 0, "l)atency: %d hours", *l); + move(LINES - 1, COLS - 1); + + for (;;) { + refresh(); + c = getch(); + switch (c) { + case 'm': + *d = MSG_MAIL; + goto redraw; + case 'p': + *d = MSG_POST; + goto redraw; + case 't': + *d = MSG_NULL; + goto redraw; + case 'q': + return (-1); + case 'd': + cl(6, 0); + printw("d)estination: "); + echo(); + wgetnstr(stdscr, *d == MSG_MAIL ? mdest : pdest, LINELEN); + noecho(); + goto redraw; + case 'l': + cl(10, 0); + printw("l)atency: "); + echo(); + wgetnstr(stdscr, line, LINELEN); + *l = strtol(line, NULL, 10); + if (*l < 0) + *l = 0; + noecho(); + goto redraw; + case 'c': + menu_chain(r, 1, *d == MSG_POST); + goto redraw; + case '\014': + goto redraw; + case '\n': + case '\r': + return (0); + case 's': + if (*d == MSG_POST) { + cl(7, 0); + printw("s)ubject: "); + echo(); + wgetnstr(stdscr, psub, LINELEN); + noecho(); + goto redraw; + } + default: + beep(); + } + } +} + +void menu_chain(char *chainstr, int chaintype, int post) + /* chaintype 0=mix 1=ek 2=newnym */ +{ + REMAILER remailer[MAXREM]; + int badchains[MAXREM][MAXREM]; + int rlist[2 * MAXREM]; + char newchain[CHAINMAX]; + char info[LINELEN]; + int num = 0, i, middlemanlast=0, ok = 1; + int c, x, y; + int nymserv = 0; + int chain[20], chainlen = 0; + char reliability[9]; + + if (chaintype == 2) + nymserv = 1, chaintype = 1; + assert(chaintype == 0 || chaintype == 1); + + clear(); + standout(); + if (nymserv) + printw("Select nym server:\n\n"); + else + printw("Select remailer chain:\n\n"); + standend(); + + if (chaintype == 1) + num = t1_rlist(remailer, badchains); + else + num = mix2_rlist(remailer, badchains); + + if (num < 1) { + mix_status("Can't read remailer list."); + beep(); + return; + } + for (i = 0; i < num; i++) { + rlist[2 * i] = i + 1; + rlist[2 * i + 1] = remailer[i + 1].info[chaintype].reliability - + remailer[i + 1].info[chaintype].latency / 3600; + if (remailer[i + 1].info[chaintype].history[0] == '\0') + rlist[2 * i + 1] = -1; + if ((nymserv && !remailer[i + 1].flags.newnym) || + ((chaintype == 0 && !remailer[i + 1].flags.mix) || + (chaintype == 1 && !nymserv && (!remailer[i + 1].flags.ek + || !remailer[i + 1].flags.pgp)))) + rlist[2 * i] = 0, rlist[2 * i + 1] = -2; + } + qsort(rlist, num - 1, 2 * sizeof(int), sortrel); + + for (i = 0; i < num; i++) + if (rlist[2 * i + 1] == -2) { + num = i; + break; + } + if (num < 1) { + mix_status("No remailers found!"); + return; + } + if (num > 2 * (LINES - 6)) + num = 2 * (LINES - 6); + if (num > 2 * 26) + num = 2 * 26; + + for (i = 0; i < num && rlist[2 * i + 1] > -2; i++) { + y = i, x = 0; + if (y >= LINES - 6) + y -= LINES - 6, x += 40; + mvprintw(y + 2, x, "%c", i < 26 ? i + 'a' : i - 26 + 'A'); + mvprintw(y + 2, x + 2, "%s", remailer[rlist[2 * i]].name); + mvprintw(y + 2, x + 16, "%s", + remailer[rlist[2 * i]].info[chaintype].history); + sprintf(info, "%3.2f", + remailer[rlist[2 * i]].info[chaintype].reliability / 100.0); + mvprintw(y + 2, x + 29 + 6 - strlen(info), "%s%%", info); + } + y = num + 3; + if (y > LINES - 4) + y = LINES - 4; + mvprintw(y, 0, "* select at random"); + + for (;;) { + newchain[0] = '\0'; + for (i = 0; i < chainlen; i++) { + if (i) + strcatn(newchain, ",", CHAINMAX); + if (chain[i]) + strcatn(newchain, remailer[chain[i]].name, CHAINMAX); + else + strcatn(newchain, "*", CHAINMAX); + } + if (chainlen > 0) { + ok = 1; + middlemanlast = remailer[chain[chainlen - 1]].flags.middle; + if (post && !remailer[chain[chainlen - 1]].flags.post && !(chain[chainlen - 1] == 0 /*randhop*/)) + ok = 0; + } else + ok = 1; + + mvprintw(LINES - 4, 40, + middlemanlast ? + "MIDDLEMAN " : + (ok ? + " " : + "NO POSTING ")); + cl(LINES - 3, 0); + cl(LINES - 2, 0); + cl(LINES - 1, 0); + if(!nymserv){ + chain_reliability(newchain, chaintype, reliability); + mvprintw(LINES - 4, 58, "(reliability: %s)", reliability); + } + mvprintw(LINES - 3, 0, nymserv ? "Nym server: %s" : "Chain: %s", + newchain); + refresh(); + c = getch(); + if (c == '\n' || c == '\r') { + /* beep and sleep in case the user made a mistake */ + if (middlemanlast) { + beep(); + sleep(2); + } + if (ok || middlemanlast) + break; + else + beep(); + } else if (c == '*') { + if (chainlen > 19 || (nymserv && chainlen > 0)) + beep(); + else + chain[chainlen++] = 0; + } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + if (c >= 'a') + c -= 'a'; + else + c = c - 'A' + 26; + + if (chainlen > 19 || (nymserv && chainlen > 0) || c >= num) + beep(); + else + chain[chainlen++] = rlist[2 * c]; + } else if (c == killchar()) + chainlen = 0; + else if ((c == KEY_BACKSPACE || c == KEY_LEFT || c == erasechar()) + && chainlen > 0) + --chainlen; + else + beep(); + } + if (chainlen) + strncpy(chainstr, newchain, CHAINMAX); +} + +#endif /* USE_NCURSES */ diff --git a/Src/menu.h b/Src/menu.h @@ -0,0 +1,48 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Menu-based user interface + $Id: menu.h 934 2006-06-24 13:40:39Z rabbi $ */ + + +#ifndef _MENU_H +#define _MENU_H +#include "mix3.h" +#ifdef USE_NCURSES +#ifdef HAVE_NCURSES_H +#include <ncurses.h> +#else /* end of HAVE_NCURSES_H */ +#include <curses.h> +#endif /* else if not HAVE_NCURSES_H */ +#endif /* USE_NCURSES */ + +#define NONANON "non-anonymous" +#define ANON "Anonymous" + +void send_message(int type, char *nym, BUFFER *txt); +void read_folder(char command, char *foldername, char *nym); +void menu_init(void); +void menu_exit(void); + +void menu_spawn_editor(char *path, int lineno); + +#ifdef USE_NCURSES +void read_message(BUFFER *message, char *nym); +void menu_nym(char *); +void menu_chain(char *chain, int type, int post); +void cl(int y, int x); +void askfilename(char *fn); +void savemsg(BUFFER *message); +int menu_replychain(int *d, int *l, char *mdest, char *pdest, char *psub, + char *r); +void update_stats(void); + +#endif /* USE_NCURSES */ + +#define maxnym 30 + +#endif /* not _MENU_H */ diff --git a/Src/menunym.c b/Src/menunym.c @@ -0,0 +1,472 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Menu-based user interface - nym management + $Id: menunym.c 934 2006-06-24 13:40:39Z rabbi $ */ + +#ifdef NYMSUPPORT + +#include "menu.h" +#include "mix3.h" +#include <string.h> +#include <stdlib.h> +#ifdef POSIX +#include <unistd.h> +#endif /* POSIX */ + +#ifdef USE_NCURSES +void menu_nym(char *nnym) +{ + char nym[maxnym][LINELEN]; + char pending[maxnym][LINELEN]; + int c, i, num = 0, numpending = 0, select = -1; + int edit = 0; + BUFFER *nymlist; + int s; + int pass = 0; + char reliability[9]; /* When printing information about a chain, + this variable stores the reliability. */ + + nymlist = buf_new(); + + strcpy(nym[0], NONANON); + strcatn(nym[0], " (", sizeof(nym[0])); + strcatn(nym[0], NAME, sizeof(nym[0])); + strcatn(nym[0], ")", sizeof(nym[0])); + + strcpy(nym[1], ANON); + num = 2; + if (nymlist_read(nymlist) == -1) { + user_delpass(); + mix_status(""); + } else + pass = 1; + while (nymlist_get(nymlist, nym[num], NULL, NULL, NULL, NULL, NULL, &s) >= 0) { + if (s == NYM_OK) { + if (num < maxnym) + num++; + } else if (s == NYM_WAITING) { + if (numpending < maxnym) + strncpy(pending[numpending++], nym[num], LINELEN); + } + } + buf_free(nymlist); + +nymselect: + clear(); + standout(); + printw("Select nym:\n\n"); + standend(); +#ifdef USE_PGP + if (pass) + printw("c)reate new nym\ne)dit nym\nd)elete nym\n\n"); + else + printw("[nym passphrase is invalid]\n\n"); +#endif /* USE_PGP */ + for (i = 0; i < num; i++) + printw("%d) %s\n", i, nym[i]); + if (numpending > 0) { + printw("\n\nWaiting for confirmation: "); + for (i = 0; i < numpending; i++) + printw("%s ", pending[i]); + printw("\n"); + } +select: + if (select != -1) + printw("\r%d", select); + else + printw("\r \r"); + refresh(); + c = getch(); + if (c == erasechar()) + c = KEY_BACKSPACE; + if (c >= '0' && c <= '9') { + if (select == -1) + select = c - '0'; + else + select = 10 * select + c - '0'; + if (edit ? select == 0 || select >= num + numpending - 1 : select >= num) { + beep(); + select = -1; + } + refresh(); + goto select; + } else + switch (c) { + case KEY_BACKSPACE: + select /= 10; + if (select < 1) + select = -1; + goto select; + case 'q': + if (edit) { + edit = 0; + select = -1; + goto nymselect; + } + break; +#ifdef USE_PGP + case 'e': + if (pass) { + if (edit || num + numpending < 3) { + edit = 0; + select = -1; + goto nymselect; + } else { + clear(); + standout(); + printw("Edit nym:\n\n"); + standend(); + for (i = 2; i < num + numpending; i++) + printw("%d) %s\n", i - 1, i < num ? nym[i] : pending[i - num]); + printw("\n"); + select = -1; + edit = NYM_MODIFY; + goto select; + } + } + break; + case 'd': + if (pass) { + if (edit || num + numpending < 3) { + edit = 0; + select = -1; + goto nymselect; + } else { + clear(); + standout(); + printw("Delete nym:\n\n"); + standend(); + for (i = 2; i < num + numpending; i++) + printw("%d) %s\n", i - 1, i < num ? nym[i] : pending[i - num]); + printw("\n"); + select = -1; + edit = NYM_DELETE; + goto select; + } + } + break; + case '\r': + case '\n': + if (select == -1 || (edit && select == 0)) { + beep(); + edit = 0; + select = -1; + goto nymselect; + } + if (!edit) { + strncpy(nnym, nym[select], LINELEN); + return; + } + /* fallthru */ + case 'c': + if (pass) { + char nymserv[LINELEN] = "*"; + char replyblock[5][CHAINMAX], dest[10][LINELEN]; + int latent[5], desttype[5]; + char mdest[LINELEN], pdest[LINELEN] = "alt.anonymous.messages", + psub[LINELEN] = ""; + int deflatent = 0, defdesttype = MSG_MAIL; + char alias[LINELEN] = ""; + BUFFER *name, *opt; + char sendchain[CHAINMAX]; + int sendnumcopies = 1, rnum = 1; + int i; + char line[LINELEN]; + int acksend = 0, signsend = 0, fixedsize = 0, disable = 0, + fingerkey = 1; + + name = buf_new(); + opt = buf_new(); + strncpy(sendchain, CHAIN, CHAINMAX); + strncpy(mdest, ADDRESS, LINELEN); + if (edit) + strncpy(alias, select + 1 < num ? nym[select + 1] : + pending[select + 1 - num], LINELEN); + if (edit == NYM_MODIFY) { + nymlist_getnym(alias, NULL, NULL, opt, name, NULL); + acksend = bufifind(opt, "+acksend"); + signsend = bufifind(opt, "+signsend"); + fixedsize = bufifind(opt, "+fixedsize"); + disable = bufifind(opt, "+disable"); + fingerkey = bufifind(opt, "+fingerkey"); + rnum = -1; + } + newnym: + if (!edit) { + clear(); + standout(); + printw("Create a nym:"); + standend(); + + mvprintw(3, 0, "Alias address: "); + echo(); + wgetnstr(stdscr, alias, LINELEN); + noecho(); + if (alias[0] == '\0') + goto end; + for (i = 0; alias[i] > ' ' && alias[i] != '@'; i++) ; + alias[i] = '\0'; + if (i == 0) + goto newnym; + mvprintw(4, 0, "Pseudonym: "); + echo(); + wgetnstr(stdscr, line, LINELEN); + noecho(); + buf_sets(name, line); + menu_chain(nymserv, 2, 0); + } + if (edit != NYM_DELETE) { + for (i = 0; i < 5; i++) { + desttype[i] = defdesttype; + latent[i] = deflatent; + dest[i][0] = '\0'; + strcpy(replyblock[i], "*,*,*,*"); + } + if (rnum != -1) { + menu_replychain(&defdesttype, &deflatent, mdest, pdest, psub, + replyblock[0]); + desttype[0] = defdesttype; + latent[0] = deflatent; + strncpy(dest[0], desttype[0] == MSG_POST ? pdest : mdest, + LINELEN); + } + } + redraw: + clear(); + standout(); + switch (edit) { + case NYM_DELETE: + printw("Delete nym:"); + break; + case NYM_MODIFY: + printw("Edit nym:"); + break; + default: + printw("Create a nym:"); + break; + } + standend(); + loop: + { + if (!edit) { + cl(2, 0); + printw("Nym: a)lias address: %s", alias); + cl(3, 0); + printw(" nym s)erver: %s", nymserv); + } + if (edit != NYM_DELETE) { + cl(4, 0); + printw(" p)seudonym: %s", name->data); + if (edit) + mvprintw(6, 0, "Nym modification:"); + else + mvprintw(6, 0, "Nym creation:"); + } + cl(7, 0); + chain_reliability(sendchain, 0, reliability); /* chaintype 0=mix */ + printw(" c)hain to nym server: %-30s (reliability: %s)", sendchain, reliability); + cl(8, 0); + printw(" n)umber of redundant copies: %d", sendnumcopies); + if (edit != NYM_DELETE) { + mvprintw(10, 0, "Configuration:\n"); + printw(" A)cknowledge sending: %s\n", acksend ? "yes" : "no"); + printw(" S)erver signatures: %s\n", signsend ? "yes" : "no"); + printw(" F)ixed size replies: %s\n", fixedsize ? "yes" : + "no"); + printw(" D)isable: %s\n", disable ? "yes" : "no"); + printw(" Finger K)ey: %s\n", fingerkey ? "yes" : "no"); + mvprintw(17, 0, "Reply chains:"); + cl(18, 0); + if (rnum == -1) + printw(" create new r)eply block"); + else { + printw(" number of r)eply chains: %2d reliability", rnum); + for (i = 0; i < rnum; i++) { + cl(i + 19, 0); + chain_reliability(replyblock[i], 1, reliability); /* 1=ek */ + printw(" %d) %30s %-31s [%s]", i + 1, + desttype[i] == MSG_NULL ? + "(cover traffic)" : dest[i], replyblock[i], + reliability); + } + } + } + move(LINES - 1, COLS - 1); + refresh(); + c = getch(); + if (edit != NYM_DELETE && c >= '1' && c <= '9' && c - '1' < rnum) { + menu_replychain(&defdesttype, &deflatent, mdest, pdest, psub, + replyblock[c - '1']); + desttype[c - '1'] = defdesttype; + latent[c - '1'] = deflatent; + strncpy(dest[c - '1'], + desttype[c - '1'] == MSG_POST ? pdest : mdest, LINELEN); + goto redraw; + } + switch (c) { + case 'A': + acksend = !acksend; + goto redraw; + case 'S': + signsend = !signsend; + goto redraw; + case 'F': + fixedsize = !fixedsize; + goto redraw; + case 'D': + disable = !disable; + goto redraw; + case 'K': + fingerkey = !fingerkey; + goto redraw; + case 'q': + edit = 0; + select = -1; + goto nymselect; + case '\014': + goto redraw; + case 'a': + cl(2, 0); + printw("Nym: a)lias address: "); + echo(); + wgetnstr(stdscr, alias, LINELEN); + noecho(); + for (i = 0; alias[i] > ' ' && alias[i] != '@'; i++) ; + alias[i] = '\0'; + if (i == 0) + goto nymselect; + goto redraw; + case 'p': + cl(4, 0); + printw(" p)seudonym: "); + echo(); + wgetnstr(stdscr, line, LINELEN); + noecho(); + if (line[0] != '\0') + buf_sets(name, line); + goto redraw; + case 'c': + menu_chain(sendchain, 0, 0); + goto redraw; + case 'n': + cl(8, 0); + printw(" n)umber of redundant copies: "); + echo(); + wgetnstr(stdscr, line, LINELEN); + noecho(); + sendnumcopies = strtol(line, NULL, 10); + if (sendnumcopies < 1 || sendnumcopies > 10) + sendnumcopies = 1; + goto redraw; + case 'r': + cl(18, 0); + printw(" number of r)eply chains: "); + echo(); + wgetnstr(stdscr, line, LINELEN); + noecho(); + i = rnum; + rnum = strtol(line, NULL, 10); + if (rnum < 1) + rnum = 1; + if (rnum > 5) + rnum = 5; + for (; i < rnum; i++) + if (dest[i][0] == '\0') { + desttype[i] = defdesttype; + latent[i] = deflatent; + strncpy(dest[i], defdesttype == MSG_POST ? pdest : + mdest, LINELEN); + } + goto redraw; + case 's': + menu_chain(nymserv, 2, 0); + goto redraw; + case '\n': + case '\r': + { + BUFFER *chains; + int err; + + if (rnum == -1) + chains = NULL; + else { + chains = buf_new(); + for (i = 0; i < rnum; i++) + if (replyblock[i][0] != '\0') { + if (desttype[i] == MSG_POST) + buf_appendf(chains, "Subject: %s\n", psub); + if (desttype[i] == MSG_MAIL) + buf_appends(chains, "To: "); + else if (desttype[i] == MSG_POST) + buf_appends(chains, "Newsgroups: "); + else + buf_appends(chains, "Null:"); + buf_appendf(chains, "%s\n", dest[i]); + buf_appendf(chains, "Chain: %s\n", replyblock[i]); + buf_appendf(chains, "Latency: %d\n\n", latent[i]); + } + } + create: + clear(); + buf_setf(opt, + " %cacksend %csignsend +cryptrecv %cfixedsize %cdisable %cfingerkey", + acksend ? '+' : '-', + signsend ? '+' : '-', + fixedsize ? '+' : '-', + disable ? '+' : '-', + fingerkey ? '+' : '-'); + if (edit) { + mix_status("Preparing nymserver configuration message..."); + err = nym_config(edit, alias, NULL, + name, sendchain, sendnumcopies, + chains, opt); + } else { + mix_status("Preparing nym creation request..."); + err = nym_config(edit, alias, nymserv, name, + sendchain, sendnumcopies, chains, + opt); + } + if (err == -3) { + beep(); + mix_status("Bad passphrase!"); + getch(); + goto create; + } + if (err != 0) { + mix_genericerror(); + beep(); + refresh(); + } else { + if (edit) + mix_status("Nymserver configuration message completed."); + else + mix_status("Nym creation request completed."); + } + if (chains) + buf_free(chains); + goto end; + } + default: + beep(); + goto loop; + } + } + end: + buf_free(name); + buf_free(opt); + return; + } +#endif /* USE_PGP */ + default: + beep(); + goto select; + } +} + +#endif /* USE_NCURSES */ +#endif /* NYMSUPPORT */ diff --git a/Src/menusend.c b/Src/menusend.c @@ -0,0 +1,556 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Menu-based user interface -- send message + $Id: menusend.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "menu.h" +#include "mix3.h" +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#ifdef POSIX +#include <unistd.h> +#else /* end of POSIX */ +#include <io.h> +#endif /* else if not POSIX */ + +void send_message(int type, char *nym, BUFFER *in) +{ + char dest[LINELEN] = "", subject[LINELEN] = ""; + char chain[CHAINMAX], thisnym[LINELEN], path[PATHMAX]; + BUFFER *chainlist, *msg, *txt, *tmp, *field, *content, *cc, *cite; + int numcopies; + int hdr = 0; /* txt buffer contains header lines */ + FILE *f; + int n, err; + +#ifdef USE_PGP + int sign = 0, encrypt = 0, key = 0; + +#endif /* USE_PGP */ +#ifdef USE_NCURSES + char reliability[9]; + int c; + char line[LINELEN]; + +#endif /* USE_NCURSES */ + msg = buf_new(); + tmp = buf_new(); + txt = buf_new(); + field = buf_new(); + content = buf_new(); + chainlist = buf_new(); + cc = buf_new(); + cite = buf_new(); + strncpy(chain, CHAIN, CHAINMAX); + numcopies = NUMCOPIES; + + mix_status(""); + strncpy(thisnym, nym, sizeof(thisnym)); + + if (in != NULL) + buf_set(txt, in); + + if (bufileft(txt, "From ")) + buf_getline(txt, field); /* ignore envelope From */ + + if (type == 'p' || type == 'm') { +#ifndef USE_NCURSES + mix_status("Invalid option to -f"); + mix_exit(); + exit(1); +#else /* end of not USE_NCURSES */ + clear(); + echo(); + if (in != NULL) + mvprintw(1, 0, "%s forwarding message...", thisnym); + if (type == 'p') + mvprintw(3, 0, "Newsgroups: "); + else + mvprintw(3, 0, "Send message to: "); + refresh(); + wgetnstr(stdscr, dest, LINELEN); + if (dest[0] == '\0') { + noecho(); + cl(3, 0); + goto quit; + } + if (txt->length == 0) { + mvprintw(4, 0, "Subject: "); + refresh(); + wgetnstr(stdscr, subject, LINELEN); + } else { + strcpy(subject, "Forwarded message"); + while (buf_getheader(txt, field, content) == 0) { + if (bufieq(field, "subject")) { + strncpy(subject, content->data, sizeof(subject)); + strcatn(subject, " (fwd)", sizeof(subject)); + } + if (bufieq(field, "from") || bufieq(field, "subject") || + bufieq(field, "date")) + buf_appendheader(tmp, field, content); + } + buf_nl(tmp); + buf_rest(tmp, txt); + buf_move(txt, tmp); + } + noecho(); +#endif /* else if USE_NCURSES */ + } else { + strcpy(subject, "Re: your mail"); + while (buf_getheader(txt, field, content) == 0) { + if (bufieq(field, "subject")) { + if (bufileft(content, "Re:")) + subject[0] = '\0'; + else + strcpy(subject, "Re: "); + strcatn(subject, content->data, sizeof(subject)); + } + if (bufieq(field, "from")) + buf_set(cite, content); + if (type == 'p' || type == 'f') { + if (dest[0] == '\0' && bufieq(field, "newsgroups")) + strncpy(dest, content->data, sizeof(dest)); + if (bufieq(field, "followup-to") && !bufieq(content, "poster")) + strncpy(dest, content->data, sizeof(dest)); + if (bufieq(field, "message-id")) + buf_appendf(tmp, "References: %b\n", content); + } else { + if (dest[0] == '\0' && bufieq(field, "from")) + strncpy(dest, content->data, sizeof(dest)); + if (bufieq(field, "reply-to")) + strncpy(dest, content->data, sizeof(dest)); + if (type == 'g' && (bufieq(field, "to") || bufieq(field, "cc"))) { + if (cc->length) + buf_appends(cc, ", "); + buf_cat(cc, content); + } + if (bufieq(field, "message-id")) + buf_appendf(tmp, "In-Reply-To: %b\n", content); + } + } + if (cc->length) + buf_appendf(tmp, "Cc: %b\n", cc); + if (tmp->length > 0) + hdr = 1; + if (hdr) + buf_nl(tmp); + + if ((type == 'f' || type == 'g') && cite->length) { + buf_appendf(tmp, "%b wrote:\n\n", cite); + } + if (type == 'r') + buf_appends(tmp, "You wrote:\n\n"); + + while (buf_getline(txt, content) != -1) + buf_appendf(tmp, "> %b\n", content); + buf_set(txt, tmp); + if (dest[0] == '\0') { +#ifdef USE_NCURSES + beep(); + mix_status("No recipient address found."); +#endif /* USE_NCURSES */ + goto quit; + } + goto edit; + } + +#ifdef USE_NCURSES +redraw: + clear(); + + for (;;) { + standout(); + mvprintw(0, 0, "Mixmaster %s - ", VERSION); + printw(type == 'p' || type == 'f' ? "posting to Usenet" : "sending mail"); + standend(); + mix_status(NULL); + cl(2, 0); +#ifdef NYMSUPPORT + printw("n)ym: %s", thisnym); +#endif /* NYMSUPPORT */ + if (!strleft(thisnym, NONANON)) { + chain_reliability(chain, 0, reliability); /* chaintype 0=mix */ + cl(4, 0); + printw("c)hain: %-35s (reliability: %s)", chain, reliability); + cl(5, 0); + printw("r)edundancy: %3d copies ", numcopies); + } + cl(7, 0); + printw("d)estination: %s", dest); + cl(8, 0); + printw("s)ubject: %s", subject); +#ifdef USE_PGP + if (type != 'p' && type != 'f') { + cl(10, 0); + printw("pgp encry)ption: "); + if (encrypt) + printw("yes"); + else + printw("no"); + } + if (!streq(thisnym, ANON)) { + cl(11, 0); + printw("p)gp signature: "); + if (sign) + printw("yes"); + else + printw("no"); + cl(12, 0); + if (key == 0) + printw("attach pgp k)ey: no"); + } +#endif /* USE_PGP */ + + if (txt->length == 0) + mvprintw(LINES - 3, 18, + "e)dit message f)ile q)uit w/o sending"); + else + mvprintw(LINES - 3, 0, + "m)ail message e)dit message f)ile q)uit w/o sending"); + move(LINES - 1, COLS - 1); + refresh(); + c = getch(); + if (c != ERR) { + mix_status(""); + if (c == '\r' || c == '\n') { /* default action is edit or mail */ + if (txt->length == 0) + c = 'e'; + else + c = 'm'; + } + switch (c) { +#ifdef NYMSUPPORT + case 'n': + menu_nym(thisnym); + goto redraw; +#endif /* NYMSUPPORT */ + case '\014': + goto redraw; + case 'd': + echo(); + cl(LINES - 3, 20); + cl(7, 14); + wgetnstr(stdscr, dest, LINELEN); + noecho(); + break; + case 's': + echo(); + cl(LINES - 3, 20); + cl(8, 10); + wgetnstr(stdscr, subject, LINELEN); + noecho(); + break; + case 'c': + menu_chain(chain, 0, (type == 'p' || type == 'f') + && streq(thisnym, ANON)); + goto redraw; + case 'r': + echo(); + cl(LINES - 5, 20); + cl(5, 13); + wgetnstr(stdscr, line, LINELEN); + numcopies = strtol(line, NULL, 10); + if (numcopies < 1 || numcopies > 10) + numcopies = 1; + noecho(); + break; + case 'f': + cl(LINES - 3, 0); + askfilename(path); + cl(LINES - 3, 0); + if (txt->length) { + buf_sets(tmp, path); + buf_clear(msg); + if (!hdr) + buf_nl(msg); + buf_cat(msg, txt); + if (attachfile(msg, tmp) == -1) + beep(); + else { + buf_move(txt, msg); + hdr = 1; + } + } else { + if ((f = fopen(path, "r")) != NULL) { + buf_clear(txt); + buf_read(txt, f); + fclose(f); + } else + beep(); + } + break; + case 'e': +#endif /* USE_NCURSES */ + { + int linecount; + + edit: + linecount = 1; + sprintf(path, "%s%cx%02x%02x%02x%02x.txt", POOLDIR, DIRSEP, + rnd_byte(), rnd_byte(), rnd_byte(), rnd_byte()); + f = fopen(path, "w"); + if (f == NULL) { +#ifdef USE_NCURSES + beep(); +#endif /* USE_NCURSES */ + } else { + if (type == 'f' || type == 'p') + fprintf(f, "Newsgroups: %s\n", dest); + if (type == 'r' || type == 'g' || type == 'm') + fprintf(f, "To: %s\n", dest); + fprintf(f, "Subject: %s\n", subject); + linecount += 2; + if (hdr) + while (buf_getline(txt, NULL) == 0) linecount++; + else + fprintf(f, "\n"); + linecount++; + if (txt->length == 0) + fprintf(f, "\n"); + + buf_write(txt, f); + fclose(f); + } + + menu_spawn_editor(path, linecount); + + f = fopen(path, "r"); + if (f == NULL) { +#ifdef USE_NCURSES + clear(); + beep(); + continue; +#else /* end of USE_NCURSES */ + goto quit; +#endif /* else if not USE_NCURSES */ + } + buf_reset(txt); + hdr = 0; + + buf_reset(tmp); + buf_read(tmp, f); + while (buf_getheader(tmp, field, content) == 0) { + if (bufieq(field, "subject")) + strncpy(subject, content->data, + sizeof(subject)); + else if ((type == 'p' || type == 'f') && + bufieq(field, "newsgroups")) + strncpy(dest, content->data, sizeof(dest)); + else if (bufieq(field, "to")) + strncpy(dest, content->data, sizeof(dest)); + else { + buf_appendheader(txt, field, content); + hdr = 1; + } + } + if (hdr) + buf_nl(txt); + buf_rest(txt, tmp); + + fclose(f); + unlink(path); + strcatn(path, "~", PATHMAX); + unlink(path); +#ifndef USE_NCURSES + { + char line[4]; + + fprintf(stderr, "Send message [y/n]? "); + scanf("%3s", line); + if (!strleft(line, "y")) + goto quit; + } +#else /* end of not USE_NCURSES */ + goto redraw; + } + break; + case 'm': + if (txt->length == 0) + beep(); + else if (dest[0] == '\0') { + mix_status("No destination given."); + goto redraw; + } else { + mix_status("Creating message..."); +#endif /* else if USE_NCURSES */ + buf_reset(msg); + + if (type == 'p' || type == 'f') + buf_appends(msg, "Newsgroups: "); + else + buf_appends(msg, "To: "); + buf_appends(msg, dest); + buf_nl(msg); + buf_appends(msg, "Subject: "); + if (subject[0] == '\0') + buf_appends(msg, "(no subject)"); + else + buf_appends(msg, subject); + buf_nl(msg); + if (!hdr) + buf_nl(msg); + buf_cat(msg, txt); +#ifdef USE_PGP + { + BUFFER *p; + + p = buf_new(); + if (streq(thisnym, ANON)) + sign = 0; + if (sign || (key && !strileft(thisnym, NONANON))) + user_pass(p); + + if (encrypt || sign) { + if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0) + | (sign ? PGP_SIGN : 0) | PGP_TEXT + | (strleft(thisnym, NONANON) ? 0 : PGP_REMAIL), + msg, strleft(thisnym, NONANON) ? + ADDRESS : thisnym, p, PGPPUBRING, + strleft(thisnym, NONANON) ? + PGPSECRING : NYMSECRING) == -1) { + mix_genericerror(); +#ifdef USE_NCURSES + beep(); + goto redraw; +#endif /* USE_NCURSES */ + } + } + buf_free(p); + } +#endif /* USE_PGP */ + + if (strleft(thisnym, NONANON)) { + FILE *f = NULL; + + if (type == 'p' || type == 'f') { + if (strchr(NEWS, '@')) { + /* NOT_IMPLEMENTED; */ + } else + f = openpipe(NEWS); + } else { + if (NAME[0]) { + buf_sets(tmp, NAME); + buf_appends(tmp, " <"); + buf_appends(tmp, ADDRESS); + buf_appends(tmp, ">"); + } else + buf_sets(tmp, ADDRESS); + mail_encode(msg, 0); + if (sendmail(msg, tmp->data, NULL) != 0) { +#ifdef USE_NCURSES + clear(); +#endif /* USE_NCURSES */ + mix_status("Error sending message."); +#ifdef USE_NCURSES + goto redraw; +#else /* end of USE_NCURSES */ + goto quit; +#endif /* else if not USE_NCURSES */ + } + } +#ifdef USE_NCURSES + clear(); +#endif /* USE_NCURSES */ + mix_status("Message sent non-anonymously."); + goto quit; + } else { +#ifdef USE_PGP +#ifdef NYMSUPPORT + if (!streq(thisnym, ANON)) { + if (nym_encrypt(msg, thisnym, (type == 'p' || type == 'f') ? + MSG_POST : MSG_MAIL) == 0) + type = 'm'; + } +#endif /* NYMSUPPORT */ +#endif /* USE_PGP */ + err = mix_encrypt((type == 'p' || type == 'f') ? + MSG_POST : MSG_MAIL, + msg, chain, numcopies, chainlist); + if (err == 0) { +#ifdef USE_NCURSES + clear(); +#endif /* USE_NCURSES */ + for (n = 0; buf_getline(chainlist, tmp) == 0; n++) ; + if (n > 1) + mix_status("Done. (%d packets)", n); + else + mix_status("Chain: %s", chainlist->data); + goto quit; + } else { +#ifdef USE_NCURSES + beep(); +#endif /* USE_NCURSES */ + if (chainlist->length) + mix_status("%s", chainlist->data); + else + mix_genericerror(); + } + } + } +#ifdef USE_NCURSES + break; + case 'q': + case 'Q': + clear(); + goto quit; +#ifdef USE_PGP + case 'p': + if (!streq(thisnym, ANON)) + sign = !sign; + break; + case 'y': + encrypt = !encrypt; + break; + case 'k': + if (!streq(thisnym, ANON)) { + BUFFER *p, *keytxt, *uid; + + key = 1; + p = buf_new(); + keytxt = buf_new(); + uid = buf_new(); + + buf_appendf(uid, "<%s>", strleft(thisnym, NONANON) ? ADDRESS : + thisnym); + user_pass(p); + pgp_pubkeycert(uid, strleft(thisnym, NONANON) ? + PGPSECRING : NYMSECRING, p, keytxt, PGP_ARMOR_NYMKEY); + + buf_clear(msg); + if (!hdr) + buf_nl(msg); + buf_cat(msg, txt); + buf_sets(p, "application/pgp-keys"); + mime_attach(msg, keytxt, p); + hdr = 1; + buf_move(txt, msg); + + buf_free(p); + buf_free(keytxt); + buf_free(uid); + } + break; +#endif /* USE_PGP */ + default: + beep(); + } + } + } +#endif /* USE_NCURSES */ +quit: + buf_free(cc); + buf_free(cite); + buf_free(msg); + buf_free(txt); + buf_free(field); + buf_free(content); + buf_free(chainlist); + buf_free(tmp); +} diff --git a/Src/menustats.c b/Src/menustats.c @@ -0,0 +1,445 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Menu-based user interface + $Id: menustats.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#if 0 +void errlog(int type, char *format, ...) { }; +char MIXDIR[512]; +#include "util.c" +#include "buffers.c" +int menu_getuserpass(BUFFER *p, int mode) { return 0; }; +#endif + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#include "menu.h" +#ifdef WIN32 +#include <urlmon.h> +#pragma comment(lib,"urlmon.lib") +#else +#include <sys/wait.h> +#endif /* WIN32 */ + + +int url_download(char *url, char *dest) { + int err; +#ifdef WIN32 + err = URLDownloadToFile(NULL, url, dest, BINDF_GETNEWESTVERSION, NULL); + + if (err != S_OK) + return -1; + else + return 0; +#else + char s[PATHMAX]; + snprintf(s, PATHMAX, "%s -q %s -O %s", WGET, url, dest); + err = system(s); + + if (err != -1) { + if (WIFEXITED(err) == 0) + return -1; /* abnormal child exit */ + else + return 0; + } + else + return -1; +#endif /* WIN32 */ +} + +/** read the allpingers file into the buffer */ +void read_allpingers(BUFFER *allpingers) { + FILE *f; + + f = mix_openfile(ALLPINGERSFILE, "r"); + if (f != NULL) { + buf_clear(allpingers); + buf_read(allpingers, f); + fclose(f); + } +} + +/* Get all sections from inifile. + * + * They are put into the sections buffer, separated by newlines + */ +void get_sections(BUFFER *inifile, BUFFER *sections) { + BUFFER *line; + int err; + + line = buf_new(); + + buf_rewind(inifile); + buf_reset(sections); + + while ((err = buf_getline(inifile, line)) != -1) { + if (bufileft (line, "[") && + bufiright(line, "]")) { + line->data[line->length-1] = '\0'; + buf_appends(sections, line->data+1); + buf_nl(sections); + }; + } + buf_free (line); +} + +/* Get value of an attribute + * + * returns -1 if it isn't found. + */ +int get_attribute(BUFFER *inifile, char *section, char *attribute, BUFFER *value) { + BUFFER *line; + int err = -1; + int insection = 0; + + line = buf_new(); + + buf_rewind(inifile); + buf_reset(value); + + while (buf_getline(inifile, line) != -1) { + if (bufileft (line, "[") && + bufiright(line, "]")) { + if (insection) + break; + + line->data[line->length-1] = '\0'; + if (strcasecmp(section, line->data+1) == 0) { + insection = 1; + } + } else if (insection && bufileft(line, attribute)) { + /* we are in the right section and this attribute name + * at least starts with what we want */ + char *ptr = line->data + strlen(attribute); + /* eat up whitespace */ + while ((*ptr == ' ') || (*ptr == '\t')) + ptr++; + if (*ptr != '=') + continue; + ptr++; + while ((*ptr == ' ') || (*ptr == '\t')) + ptr++; + buf_appends(value, ptr); + err = 0; + break; + } + } + buf_free (line); + return (err); +} + + + + + +static char *files[] = { "mlist", "rlist", "mixring", "pgpring"}; +#define NUMFILES sizeof(files)/sizeof(*files) + +/* Download all the needed files from the specified source */ +/* returns -1 on error */ +int stats_download(BUFFER *allpingers, char *sourcename, int curses) { + char *localfiles[] = { TYPE2REL, TYPE1LIST, PUBRING, PGPREMPUBASC }; + char path[PATHMAX]; + char path_t[PATHMAX]; + BUFFER *value; + int ret = 0; + int err; + int i; + + value = buf_new(); + + if (curses) { + clear(); + } + + err = get_attribute(allpingers, sourcename, "base", value); + if (err == 0) { + if (curses) { + standout(); + printw("%s", value->data); + standend(); + } + else + printf("%s\n\r", value->data); + } + +/* Loop to get each file in turn to a temp file */ + + for (i=0; i<NUMFILES; i++) { + err = get_attribute(allpingers, sourcename, files[i], value); + if (err < 0) { + /* the attribute vanished under us */ + ret = -1; + break; + } + mixfile(path, localfiles[i]); + if (curses) { + mvprintw(i+3, 0, "downloading %s from %s...", localfiles[i], value->data); + refresh(); + } + else + printf("downloading %s from %s...", localfiles[i], value->data); + err = url_download(value->data, strcat(path, ".t")); + if (err < 0) { + if (curses) + printw("failed to download.\n\rTry using another stats source."); + else + printf("failed to download.\n\rTry using another stats source.\n\r"); + ret = -1; + break; + } + if (curses) + printw("done"); + else + printf("done\n\r"); + } + +/* We got them all ok - so rename them to their correct names */ + + for (i=0; i<NUMFILES; i++) { + mixfile(path, localfiles[i]); + mixfile(path_t, localfiles[i]); + strcat(path_t, ".t"); + rename(path_t, path); + } + + if (curses) { + printw("\n\n\n\n\rPress any key to continue"); + getch(); + clear(); + } + buf_free(value); + return ret; +} +/* Checks whether the stats source has all the required files. + * + * 1 if it has, + * 0 otherwise + */ +int good_stats_source (BUFFER *allpingers, char *sourcename) { + BUFFER *value; + int i; + int res = 1; + int err; + + value = buf_new(); + + for (i = 0; i < NUMFILES; i++) { + err = get_attribute(allpingers, sourcename, files[i], value); + if (err < 0) { + res = 0; + break; + } + } + + buf_free (value); + return (res); +} + +/* Do a stats download update and report status */ +/* 0 on success */ +/* -1 File download failed */ +/* -2 Error writing file */ +/* -3 Stats source incomplete */ + +int download_stats(char *sourcename) { + BUFFER *inifile; + FILE *f; + int ret; + inifile = buf_new(); + read_allpingers(inifile); + if (good_stats_source(inifile, sourcename) == 1) { + if (stats_download(inifile, sourcename, 0) == 0) { + f = mix_openfile(STATSSRC, "w+"); + if (f != NULL) { + fprintf(f, "%s", sourcename); + fclose(f); + ret = 0; + } else { + ret = -2; + errlog(ERRORMSG, "Could not open stats source file for writing.\n"); + } + } else { + ret = -1; + errlog(ERRORMSG, "Stats source download failed.\n"); + } + } else { + ret = -3; + errlog(ERRORMSG, "Stats source does not include all required files.\n"); + } + + buf_free(inifile); + return (ret); +} + + +/* Download allpingers.txt */ +/* -1 on error */ +static int download_list() { + char path[PATHMAX]; + + mixfile(path, ALLPINGERSFILE); + + clear(); + standout(); + printw(ALLPINGERSURL); + standend(); + + mvprintw(3,0,"downloading %s...", ALLPINGERSURL); + refresh(); + if (url_download(ALLPINGERSURL, path) < 0) { + printw("failed to download.\n\rTry again later."); + printw("\n\n\rPress any key to continue"); + getch(); + return -1; + } + return 0; +} + +/* Displays the choice of stats sources */ +#define MAXPING (26 * 2) +void update_stats() { + char c; + BUFFER *inifile; + BUFFER *pingernames; + BUFFER *goodpingers; + BUFFER *line; + BUFFER *statssrc; + FILE *f; + int num; + int err; + int x, y; + int i; + + inifile = buf_new(); + pingernames = buf_new(); + goodpingers = buf_new(); + line = buf_new(); + statssrc = buf_new(); + + while (1) { + clear(); + standout(); + buf_clear(statssrc); + f = mix_openfile(STATSSRC, "r"); + if (f != NULL) { + buf_read(statssrc, f); + fclose(f); + } + printw("Select stats source:"); + standend(); + if (statssrc->length > 0) + printw(" Current: %s (Enter to download)", statssrc->data); + printw("\n\n"); + + read_allpingers(inifile); + get_sections (inifile, pingernames); + + num = 0; + buf_reset(goodpingers); + buf_rewind(pingernames); + while ((buf_getline(pingernames, line) != -1) && num < MAXPING) { + if (good_stats_source (inifile, line->data)) { + buf_cat(goodpingers, line); + buf_nl(goodpingers); + num++; + } + } + + x = 0; + buf_rewind(goodpingers); + for (i=0; i<num; i++) { + err = buf_getline(goodpingers, line); + assert (err != -1); + y = i; + if (y >= LINES - 6) + y -= LINES - 6, x = 40; + mvprintw(y + 2, x, "%c", i < 26 ? i + 'a' : i - 26 + 'A'); + mvprintw(y + 2, x + 2, "%s", line->data); + } + y = i + 3; + if (y > LINES - 4) + y = LINES - 4; + mvprintw(y, 0, "* update list of pingers from web = edit list <space> to exit"); + c = getch(); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + if (c >= 'a') + c -= 'a'; + else + c = c - 'A' + 26; + if (c < num) { + buf_rewind(goodpingers); + while (c >= 0) { + err = buf_getline(goodpingers, line); + assert (err != -1); + c--; + } + if (stats_download(inifile, line->data, 1) == 0) { + f = mix_openfile(STATSSRC, "w+"); + if (f != NULL) { + fprintf(f, "%s", line->data); + fclose(f); + } else + fprintf(stderr, "Could not open stats source file for writing\n"); + break; + } + } + } + else if (c == '*') { + download_list(); + } + else if (c == '=') { + char path[PATHMAX]; + mixfile(path, ALLPINGERSFILE); + menu_spawn_editor(path, 0); + } + else if ((c == '\r') && statssrc->length) { + stats_download(inifile, statssrc->data, 1); + break; + } + else if (c == ' ') { + break; + } + } + clear(); + + buf_free(statssrc); + buf_free(inifile); + buf_free(line); + buf_free(pingernames); + buf_free(goodpingers); +} + +#if 0 +int main() { + strcpy(MIXDIR,"./"); + + BUFFER *allpingers; + BUFFER *pingernames; + BUFFER *value; + + allpingers = buf_new(); + pingernames = buf_new(); + value = buf_new(); + + read_allpingers (allpingers); + get_sections (allpingers, pingernames); + + printf("%s", pingernames->data); + + get_attribute (allpingers, "noreply", "rlist", value); + printf("%s\n", value->data); + + + exit(0); +} + +#endif diff --git a/Src/menuutil.c b/Src/menuutil.c @@ -0,0 +1,154 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Menu-based user interface - utility functions + $Id: menuutil.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "menu.h" +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +int menu_initialized = 0; + +#ifdef USE_NCURSES +void cl(int y, int x) +{ + move(y, x); + hline(' ', COLS - x); +} +#endif /* USE_NCURSES */ + +void menu_init(void) +{ +#ifdef USE_NCURSES + initscr(); + cbreak(); + noecho(); + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + menu_initialized = 1; +#endif /* USE_NCURSES */ +} + +void menu_exit(void) +{ + user_delpass(); +#ifdef USE_NCURSES + endwin(); +#endif /* USE_NCURSES */ +} + +#ifdef USE_NCURSES +void askfilename(char *path) +{ + char line[PATHMAX]; + + printw("\rFile name: "); + echo(); + wgetnstr(stdscr, path, PATHMAX); + noecho(); + printw("\r"); + if (path[0] == '~') { + char *h; + + if ((h = getenv("HOME")) != NULL) { + strncpy(line, h, PATHMAX); + strcatn(line, "/", PATHMAX); + strcatn(line, path + 1, PATHMAX); + strncpy(path, line, PATHMAX); + } + } +} + +void savemsg(BUFFER *message) +{ + char savename[PATHMAX]; + FILE *f; + + askfilename(savename); + f = fopen(savename, "a"); + if (f != NULL) { + buf_write(message, f); + fclose(f); + } +} + +#endif /* USE_NCURSES */ + +void menu_spawn_editor(char *path, int lineno) { +#ifdef WIN32 + SHELLEXECUTEINFO sei; + ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO)); + sei.cbSize = sizeof(SHELLEXECUTEINFO); + sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; + sei.hwnd = NULL; + sei.lpVerb = "open"; + sei.lpFile = path; + sei.lpParameters = NULL; + sei.nShow = SW_SHOWNORMAL; + + if (ShellExecuteEx(&sei) == TRUE) { + WaitForSingleObject(sei.hProcess, INFINITE); + CloseHandle(sei.hProcess); + } +#else /* WIN32 */ + char *editor; + char s[PATHMAX]; + +/* Command line option +nn to position the cursor? */ +#define cursorpos (strfind(editor, "emacs") || streq(editor, "vi") || \ + streq(editor, "joe")) + + editor = getenv("EDITOR"); + if (editor == NULL) + editor = "vi"; + + if (lineno > 1 && cursorpos) + snprintf(s, PATHMAX, "%s +%d %s", editor, lineno, path); + else + snprintf(s, PATHMAX, "%s %s", editor, path); + +#ifdef USE_NCURSES + clear(); + refresh(); + endwin(); +#endif /* USE_NCURSES */ + system(s); +#ifdef USE_NCURSES + refresh(); +#endif /* USE_NCURSES */ + +#endif /* WIN32 */ +} + +int menu_getuserpass(BUFFER *b, int mode) +{ +#ifdef USE_NCURSES + char p[LINELEN]; + + if (menu_initialized) { + cl(LINES - 1, 10); + if (mode == 0) + printw("enter passphrase: "); + else + printw("re-enter passphrase: "); + wgetnstr(stdscr, p, LINELEN); + cl(LINES - 1, 10); + refresh(); + if (mode == 0) + buf_appends(b, p); + else + return (bufeq(b, p)); + return (0); + } +#endif /* USE_NCURSES */ + return (-1); +} diff --git a/Src/mime.c b/Src/mime.c @@ -0,0 +1,814 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + MIME functions + $Id: mime.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <ctype.h> +#include <string.h> + +#define hex(i) (isdigit(i) ? (i) - '0' : tolower(i) - 'a' + 10) + +#define hexdigit(i) ((byte)(i < 10 ? i + '0' : i - 10 + 'A')) + +static void encode_word(BUFFER *in) +{ + BUFFER *out; + int i; + + out = buf_new(); + for (i = 0; i < in->length; i++) + if (in->data[i] < 32 || in->data[i] >= 127 || in->data[i] == '=' + || in->data[i] == '?' || in->data[i] == '_') { + buf_appendc(out, '='); + buf_appendc(out, hexdigit(in->data[i] / 16)); + buf_appendc(out, hexdigit(in->data[i] % 16)); + } else if (in->data[i] == ' ') + buf_appendc(out, '_'); + else + buf_appendc(out, in->data[i]); + buf_move(in, out); + buf_free(out); +} + +void body_encode(BUFFER *in, int transport, BUFFER *hdr) +{ + BUFFER *out; + int c, l=0, encoding = 0; + out = buf_new(); + + buf_clear(hdr); + + l = in->ptr; + while ((c = buf_getc(in)) != -1 && encoding != 2) { + if (c >= 160) + encoding = 1; + else if (c == ' ') { + if (buf_getc(in) == '\n') + encoding = 1; + buf_ungetc(in); + } else if ((c < 32 && c != ' ' && c != '\n' && c != '\t') || + (c >= 127 && c < 160)) { + encoding = 2; + } + } + in->ptr = l; + + if (encoding == 2) { + buf_sets(hdr, "Content-Transfer-Encoding: base64\n"); + encode(in, 76); + } else { + +#if 0 + if (encoding == 0) + buf_sets(hdr, "Content-Transfer-Encoding: 7bit\n"); +#endif + if (encoding != 0 && transport == MIME_8BIT) + buf_sets(hdr, "Content-Transfer-Encoding: 8bit\n"); + if (encoding == 0 || transport == MIME_8BIT) { + buf_rest(out, in); /* transparent */ + buf_move(in, out); + } else { + buf_sets(hdr, "Content-Transfer-Encoding: quoted-printable\n"); + l = 0; + while ((c = buf_getc(in)) != -1) { + if (c == '\n') { + buf_nl(out); + l = 0; + } + else if (c < 32 || c >= 127 || c == '=') { + if (l > 73) { + buf_appends(out, "=\n"); + l = 0; + } + buf_appendc(out, '='); + buf_appendc(out, hexdigit(c / 16)); + buf_appendc(out, hexdigit(c % 16)); + l += 3; + } else if (c == ' ') { + if (buf_getc(in) == '\n') { + buf_appendc(out, '='); + buf_appendc(out, hexdigit(c / 16)); + buf_appendc(out, hexdigit(c % 16)); + buf_nl(out); + l = 0; + } else { + buf_appendc(out, c); + buf_ungetc(in); + l++; + } + } else { + buf_appendc(out, c); + l++; + } + } + buf_move(in, out); + } + } + buf_free(out); +} + +int mail_encode(BUFFER *in, int encoding) +{ + BUFFER *out, *line, *tmp; + + out = buf_new(); + line = buf_new(); + tmp = buf_new(); + + while (buf_getline(in, line) == 0) { + hdr_encode(line, 255); + buf_cat(out, line); + buf_nl(out); + } + if (in->ptr < in->length) { + /* no newline if only encoding header lines */ + if (encoding == 0) { + buf_nl(out); + buf_rest(out, in); + } + else { + body_encode(in, encoding, line); + buf_cat(out, line); + buf_nl(out); + buf_cat(out, in); + } + } + buf_move(in, out); + buf_free(line); + buf_free(tmp); + buf_free(out); + return (0); +} + +int hdr_encode(BUFFER *in, int n) +{ + int i; + int encodeword = 0, encode = 0; + BUFFER *out, *word, *space; + + out = buf_new(); + word = buf_new(); + space = buf_new(); + for (i = 0; i <= in->length; i++) { + if (isspace(in->data[i]) || in->data[i] == '\0') { + if (word->length) { + if (encodeword) { + if (encode == 0) { + buf_cat(out, space); + buf_clear(space); + buf_appends(out, "=?"); + buf_appends(out, MIMECHARSET); + buf_appends(out, "?Q?"); + encode = 1; + } else { + buf_cat(space, word); + buf_move(word, space); + } + encode_word(word); + } + if (encode && !encodeword) { + encode = 0; + buf_appends(out, "?="); + } + buf_cat(out, space); + buf_cat(out, word); + encodeword = 0; + buf_clear(space); + buf_clear(word); + } + buf_appendc(space, in->data[i]); + } else { + if (in->data[i] < 32 || in->data[i] >= 127) + encodeword = 1; + buf_appendc(word, in->data[i]); + } + } + if (encode) + buf_appends(out, "?="); + + buf_move(in, out); + while (n > 0 && in->length - in->ptr > n) { + for (i = 1; i < in->length - in->ptr; i++) + if (isspace(in->data[in->length - i])) + break; + buf_get(in, out, in->length - i); + buf_appends(out, "\n\t"); + } + buf_rest(out, in); + buf_move(in, out); + buf_free(out); + buf_free(space); + buf_free(word); + return (0); +} + +void addprintable(BUFFER *out, int c) +{ + if (c == '\n') + buf_appendc(out, (char) c); + else if (c == '\t') + buf_appends(out, " "); + else if (c == '\014') + buf_appends(out, "^L"); + else if (c == '\r') ; + else if (c <= 31 || (c >= 128 && c <= 128 + 31)) + buf_appendc(out, '?'); + else + buf_appendc(out, (char) c); +} + +void addprintablebuf(BUFFER *out, BUFFER *in) +{ + int c; + + while ((c = buf_getc(in)) != -1) + addprintable(out, c); +} + +int decode_line(BUFFER *line) +{ + BUFFER *out; + unsigned int i; + int c, softbreak = 0; + + out = buf_new(); + for (i = 0; line->data[i] != '\0'; i++) { + if (line->data[i] == '=') { + if (isxdigit(line->data[i + 1]) && isxdigit(line->data[i + 2])) { + c = hex(line->data[i + 1]) * 16 + hex(line->data[i + 2]); + i += 2; + addprintable(out, c); + } else if (line->data[i + 1] == '\0') { + softbreak = 1; + break; + } + } else + addprintable(out, line->data[i]); + } + + buf_move(line, out); + buf_free(out); + return (softbreak); +} + +int decode_header(BUFFER *in) +{ + int encoded = 0; + int c; + int err = 0; + int last = 0; + BUFFER *out; + + out = buf_new(); + for (in->ptr = 0; in->data[in->ptr] != '\0'; in->ptr++) { + if (encoded == 'q' && in->data[in->ptr] == '=' && + isxdigit(in->data[in->ptr + 1]) + && isxdigit(in->data[in->ptr + 2])) { + c = hex(in->data[in->ptr + 1]) * 16 + hex(in->data[in->ptr + 2]); + in->ptr += 2; + addprintable(out, c); + } else if (encoded == 'q' && in->data[in->ptr] == '_') + buf_appendc(out, ' '); + else if (in->data[in->ptr] == '=' && in->data[in->ptr + 1] == '?' && + in->data[in->ptr + 2] != '\0') { + if (last > 0 && out->length > last) { + out->data[last] = '\0'; + out->length = last; + } + in->ptr++; + while (in->data[++in->ptr] != '?') + if (in->data[in->ptr] == 0) { + err = -1; + goto end; + } + if (in->data[in->ptr + 1] != '\0' && in->data[in->ptr + 2] == '?') { + encoded = tolower(in->data[in->ptr + 1]); + in->ptr += 2; + if (encoded == 'b') { + BUFFER *tmp; + + tmp = buf_new(); + decode(in, tmp); + addprintablebuf(out, tmp); + last = out->length; + buf_free(tmp); + } else if (encoded != 'q') + err = 1; + } else { + err = -1; + goto end; + } + } else if (encoded && in->data[in->ptr] == '?' && + in->data[in->ptr + 1] == '=') { + in->ptr++; + last = out->length; + encoded = 0; + } else { + addprintable(out, in->data[in->ptr]); + if (!encoded || !isspace(in->data[in->ptr])) + last = out->length; + } + } +end: + if (err == -1) + buf_set(out, in); + + buf_move(in, out); + buf_free(out); + return (err); +} + +#define delimclose 2 + +int boundary(BUFFER *line, BUFFER *boundary) +{ + int c; + + if (boundary->length == 0 || !bufleft(line, "--") || + !strleft(line->data + 2, boundary->data)) + return (0); + line->ptr = boundary->length + 2; + for (;;) { + c = buf_getc(line); + if (c == -1) + return (1); + if (c == '-' && buf_getc(line) == '-') + return (delimclose); + if (!isspace(c)) + return (0); + } +} + +#define pgpenc 1 +#define pgpsig 2 + +/* + * decodes non-multipart quoted printable message + */ +int qp_decode_message(BUFFER *msg) +{ + BUFFER *out, *line, *field, *content; + out = buf_new(); + line = buf_new(); + field = buf_new(); + content = buf_new(); + + buf_rewind(msg); + + /* copy over headers without decoding */ + while (buf_getheader(msg, field, content) == 0) { + if (bufieq(field, "content-transfer-encoding") + && bufieq(content, "quoted-printable")) { + continue; /* no longer quoted-printable */ + } else { + buf_appendheader(out, field, content); + } + } + + buf_nl(out); + + /* copy over body, quoted-printable decoding as we go */ + while (buf_getline(msg, line) != -1) { + int softbreak; + softbreak = decode_line(line); + buf_cat(out, line); + if (!softbreak) + buf_nl(out); + } + buf_move(msg, out); + buf_free(out); + buf_free(line); + buf_free(field); + buf_free(content); + return 0; +} + + +int entity_decode(BUFFER *msg, int message, int mptype, BUFFER *data) +{ + BUFFER *out, *line, *field, *content, *type, *subtype, *disposition, + *mboundary, *part, *sigdata; + int ret = 0, ptype = 0, partno = 0; + int p, encoded = 0; + + out = buf_new(); + line = buf_new(); + field = buf_new(); + content = buf_new(); + type = buf_new(); + subtype = buf_new(); + disposition = buf_new(); + mboundary = buf_new(); + part = buf_new(); + sigdata = buf_new(); + + if (message && bufileft(msg, "From ")) { + buf_getline(msg, out); /* envelope from */ + buf_nl(out); + } + + while (buf_getheader(msg, field, content) == 0) { + if (bufieq(field, "content-transfer-encoding") && + bufieq(content, "quoted-printable")) + encoded = 'q'; + if (bufieq(field, "content-type")) { + get_type(content, type, subtype); + if (bufieq(type, "multipart")) + get_parameter(content, "boundary", mboundary); + if (bufieq(type, "multipart") && bufieq(subtype, "encrypted")) { + get_parameter(content, "protocol", line); + if (bufieq(line, "application/pgp-encrypted")) + ptype = pgpenc; + } + if (bufieq(type, "multipart") && bufieq(subtype, "signed")) { + get_parameter(content, "protocol", line); + if (bufieq(line, "application/pgp-signature")) + ptype = pgpsig; + } + } + if (bufieq(field, "content-disposition")) + buf_set(disposition, content); + if (message) { + decode_header(content); + buf_appendheader(out, field, content); + } + } + + if (message) + buf_nl(out); + + if (bufifind(disposition, "attachment")) { + buf_appendf(out, "[-- %b attachment", type); + get_parameter(disposition, "filename", line); + if (line->length) + buf_appendf(out, " (%b)", line); + buf_appends(out, " --]\n"); + } + + if (mboundary->length) { + /* multipart */ + while (buf_getline(msg, line) > -1 && !boundary(line, mboundary)) + ; /* ignore preamble */ + while (buf_getline(msg, line) != -1) { + p = boundary(line, mboundary); + if (p) { + if (part->data[part->length - 1] == '\n') + part->data[--(part->length)] = '\0'; + partno++; + if (ptype == pgpsig && partno == 1) + buf_set(sigdata, part); + ret += entity_decode(part, 0, ptype, sigdata); + buf_cat(out, part); + buf_clear(part); + if (p == delimclose) + break; + if (bufieq(subtype, "alternative") && ret > 0) + break; + if (bufieq(subtype, "mixed")) + buf_appends(out, + "[-------------------------------------------------------------------------]\n"); + } else { + buf_cat(part, line); + buf_nl(part); + } + } + } else if (mptype == pgpenc && bufieq(type, "application") && + bufieq(subtype, "pgp-encrypted")) { + /* application/pgp-encrypted part of multipart/encrypted */ + ; /* skip */ + } else if (mptype == pgpenc && bufieq(type, "application") && + bufieq(subtype, "octet-stream")) { + /* application/octet-stream part of multipart/encrypted */ + int ok = 0; + buf_getline(msg, line); + if (bufleft(line, info_beginpgp)) { + if (buffind(line, "(SIGNED)")) { + buf_getline(msg, line); + buf_appends(out, "[-- OpenPGP message with signature --]\n"); + if (bufleft(line, info_pgpsig)) + buf_appendf(out, "[%s]\n", + line->data + sizeof(info_pgpsig) - 1); + else + buf_appends(out, "[Signature invalid]\n"); + } else + buf_appends(out, "[-- OpenPGP message --]\n"); + while (buf_getline(msg, line) != -1) { + if (bufleft(line, info_endpgp)) { + ret += entity_decode(part, 0, 0, NULL); + buf_cat(out, part); + buf_appends(out, "[-- End OpenPGP message --]\n"); + ok = 1, ret++; + break; + } + buf_cat(part, line); + buf_nl(part); + } + } + if (!ok) { + buf_appends(out, "[-- Bad OpenPGP message --]\n"); + buf_cat(out, msg); + } + } else if (mptype == pgpsig && bufeq(type, "application") && + bufieq(subtype, "pgp-signature")) { + buf_rest(part, msg); +#ifdef USE_PGP + if (pgp_decrypt(part, NULL, data, PGPPUBRING, NULL) == PGP_SIGOK) + buf_appendf(out, "[-- OpenPGP signature from:\n %b --]\n", data); + else + buf_appends(out, "[-- Invalid OpenPGP signature --]\n"); +#else /* USE_PGP */ + buf_appends(out, "[-- No OpenPGP support --]\n"); +#endif /* !USE_PGP */ + } else if (type->length == 0 || bufieq(type, "text")) { + while (buf_getline(msg, line) != -1) { + int softbreak; + softbreak = encoded ? decode_line(line) : 0; + buf_cat(out, line); + if (!softbreak) + buf_nl(out); + } + ret++; + } else { + buf_appendf(out, "[-- %b/%b message part --]\n", type, subtype); + buf_cat(out, msg); + } + + buf_move(msg, out); + buf_free(line); + buf_free(out); + buf_free(field); + buf_free(content); + buf_free(type); + buf_free(subtype); + buf_free(disposition); + buf_free(mboundary); + buf_free(part); + buf_free(sigdata); + return (0); +} + +void mimedecode(BUFFER *msg) +{ + entity_decode(msg, 1, 0, NULL); +} + +int attachfile(BUFFER *message, BUFFER *filename) +{ + BUFFER *type, *attachment; + FILE *f; + int ret = -1; + + type = buf_new(); + attachment = buf_new(); + + if ((bufiright(filename, ".txt") || !bufifind(filename, ".")) &&(strlen(DEFLTENTITY) != 0)) + buf_sets(type, DEFLTENTITY); + else if (bufiright(filename, ".htm") || bufiright(filename, ".html")) + buf_sets(type, "text/html"); + else if (bufiright(filename, ".jpeg")) + buf_sets(type, "image/jpeg"); + else if (bufiright(filename, ".gif")) + buf_sets(type, "image/gif"); + else if (bufiright(filename, ".pcm")) + buf_sets(type, "audio/basic"); + else if (bufiright(filename, ".mpg") || bufiright(filename, ".mpeg")) + buf_sets(type, "video/mpeg"); + else if (bufiright(filename, ".ps")) + buf_sets(type, "application/postscript"); + else + buf_sets(type, "application/octet-stream"); + + f = fopen(filename->data, "r"); + if (f) { + buf_read(attachment, f); + fclose(f); + ret = mime_attach(message, attachment, type); + } + + buf_free(attachment); + buf_free(type); + return(ret); +} + +int mime_attach(BUFFER *message, BUFFER *attachment, BUFFER *attachtype) +{ + BUFFER *out, *part, *line, *type, *subtype, *mboundary, *field, *content; + int mimeheader = 0, multipart = 0, versionheader = 0; + + out = buf_new(); + line = buf_new(); + part = buf_new(); + type = buf_new(); + subtype = buf_new(); + mboundary = buf_new(); + field = buf_new(); + content = buf_new(); + + buf_rewind(message); + while (buf_getheader(message, field, content) == 0) { + if (bufieq(field, "mime-version")) + versionheader = 1; + if (bufieq(field, "content-type")) { + get_type(content, type, subtype); + if (bufieq(type, "multipart") && bufieq(subtype, "mixed")) { + multipart = 1; + get_parameter(content, "boundary", mboundary); + } + } + if (bufileft(field, "content-")) + mimeheader = 1; + } + + if (mimeheader && !multipart) { + buf_rewind(message); + while (buf_getheader(message, field, content) == 0) { + if (bufileft(field, "content-")) + buf_appendheader(part, field, content); + else + buf_appendheader(out, field, content); + } + } else { + buf_ungetc(message); + buf_append(out, message->data, message->ptr); + buf_getc(message); + } + + if (!versionheader) + buf_appends(out, "MIME-Version: 1.0\n"); + + if (!multipart) { + buf_setrnd(mboundary, 18); + encode(mboundary, 0); + buf_appendf(out, "Content-Type: multipart/mixed; boundary=\"%b\"\n", + mboundary); + } + buf_nl(out); + + if (multipart) { + while (buf_getline(message, line) != -1) { + if (boundary(line, mboundary) == delimclose) + break; + buf_cat(out, line); + buf_nl(out); + } + } else { + buf_appendf(out, "--%b\n", mboundary); + if (part->length) { + buf_cat(out, part); /* body part header */ + } + else { + if (strlen(DEFLTENTITY)) + buf_appendf(out, "Content-Type: %s\n", DEFLTENTITY); + } + + buf_nl(out); + buf_cat(out, message); + buf_nl(out); + } + + buf_appendf(out, "--%b\n", mboundary); + buf_appendf(out, "Content-Type: %b\n", attachtype); + + body_encode(attachment, MIME_8BIT, line); + buf_cat(out, line); + buf_nl(out); + buf_cat(out, attachment); + buf_appendf(out, "\n--%b--\n", mboundary); + + buf_move(message, out); + + buf_free(out); + buf_free(line); + buf_free(part); + buf_free(type); + buf_free(subtype); + buf_free(mboundary); + buf_free(field); + buf_free(content); + return (1); +} + +static int entity_encode(BUFFER *message, BUFFER *out, BUFFER *messagehdr, + int encoding) +{ + BUFFER *field, *content, *mboundary, *part, *line, *line2, *tmp; + + field = buf_new(); + content = buf_new(); + mboundary = buf_new(); + part = buf_new(); + line = buf_new(); + line2 = buf_new(); + tmp = buf_new(); + + buf_rewind(message); + buf_clear(out); + buf_clear(messagehdr); + + while (buf_getheader(message, field, content) == 0) { + if (bufileft(field, "content-")) + buf_appendheader(out, field, content); + else if (messagehdr) + buf_appendheader(messagehdr, field, content); + + if (bufieq(field, "content-type")) { + get_type(content, line, tmp); + if (bufieq(line, "multipart")) + get_parameter(content, "boundary", mboundary); + } + } + + buf_nl(out); + if (mboundary->length) { + while (buf_getline(message, line) != -1) { + buf_cat(out, line); + buf_nl(out); + if (boundary(line, mboundary)) + break; + } + while (buf_getline(message, line) != -1) { + if (boundary(line, mboundary)) { + entity_encode(part, tmp, line2, encoding); + buf_cat(out, line2); + buf_cat(out, tmp); + buf_cat(out, line); + buf_nl(out); + buf_clear(part); + if (boundary(line, mboundary) == delimclose) + break; + } else { + buf_cat(part, line); + buf_nl(part); + } + } + } else + buf_rest(out, message); + buf_rewind(out); + mail_encode(out, encoding); + + buf_free(field); + buf_free(content); + buf_free(mboundary); + buf_free(part); + buf_free(line); + buf_free(line2); + buf_free(tmp); + return (1); +} + +int pgpmime_sign(BUFFER *message, BUFFER *uid, BUFFER *pass, char *secring) +{ +#ifndef USE_PGP + return (-1) +#else /* end of not USE_PGP */ + BUFFER *out, *body, *mboundary, *algo; + int err; + + out = buf_new(); + body = buf_new(); + mboundary = buf_new(); + algo = buf_new(); + + pgp_signhashalgo(algo, uid, secring, pass); + + entity_encode(message, body, out, MIME_7BIT); + + buf_setrnd(mboundary, 18); + encode(mboundary, 0); + buf_appendf(out, "Content-Type: multipart/signed; boundary=\"%b\";\n", + mboundary); + buf_appendf(out, + "\tmicalg=pgp-%b; protocol=\"application/pgp-signature\"\n", + algo); + buf_nl(out); + + buf_appendf(out, "--%b\n", mboundary); + buf_cat(out, body); + buf_nl(out); + buf_appendf(out, "--%b\n", mboundary); + + err = pgp_encrypt(PGP_SIGN | PGP_TEXT | PGP_DETACHEDSIG, body, NULL, + uid, pass, NULL, secring); + + buf_appends(out, "Content-Type: application/pgp-signature\n"); + buf_nl(out); + buf_cat(out, body); + buf_nl(out); + buf_appendf(out, "--%b--\n", mboundary); + if (err == 0) + buf_move(message, out); + + buf_free(out); + buf_free(body); + buf_free(mboundary); + buf_free(algo); + return (err); +#endif /* else if USE_PGP */ +} diff --git a/Src/mix.c b/Src/mix.c @@ -0,0 +1,1262 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Mixmaster initialization, configuration + $Id: mix.c 962 2007-11-19 13:42:41Z zax $ */ + + +#include "mix3.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef POSIX +#include <signal.h> +#include <unistd.h> +#include <pwd.h> +#include <sys/utsname.h> +#else /* end of POSIX */ +#include <io.h> +#include <direct.h> +#endif /* else if not POSIX */ +#ifdef WIN32 +#include <windows.h> +#include <shlobj.h> +#include <shlobj.h> +#endif /* WIN32 */ +#include <assert.h> +#include "menu.h" + +int buf_vappendf(BUFFER *b, char *fmt, va_list args); + +/** filenames ************************************************************/ +char MIXCONF[PATHMAX] = DEFAULT_MIXCONF; +char DISCLAIMFILE[PATHMAX]; +char FROMDSCLFILE[PATHMAX]; +char MSGFOOTERFILE[PATHMAX]; +char POP3CONF[PATHMAX]; +char HELPFILE[PATHMAX]; +char REQUESTDIR[PATHMAX]; +char ABUSEFILE[PATHMAX]; +char REPLYFILE[PATHMAX]; +char USAGEFILE[PATHMAX]; +char USAGELOG[PATHMAX]; +char BLOCKFILE[PATHMAX]; +char ADMKEYFILE[PATHMAX]; +char KEYFILE[PATHMAX]; +char PGPKEY[PATHMAX]; +char DSAPARAMS[PATHMAX]; +char DHPARAMS[PATHMAX]; +char MIXRAND[PATHMAX]; +char SECRING[PATHMAX]; +char PUBRING[PATHMAX]; +char IDLOG[PATHMAX]; +char STATS[PATHMAX]; +char PGPMAXCOUNT[PATHMAX]; +char DESTBLOCK[PATHMAX]; +char DESTALLOW[PATHMAX]; +char DESTALLOW2[PATHMAX]; +char SOURCEBLOCK[PATHMAX]; +char HDRFILTER[PATHMAX]; +char REGULAR[PATHMAX]; +char POOL[PATHMAX]; +char TYPE1LIST[PATHMAX]; +char TYPE2REL[PATHMAX]; +char PIDFILE[PATHMAX]; + +char PGPREMPUBRING[PATHMAX]; +char PGPREMPUBASC[PATHMAX]; +char PGPREMSECRING[PATHMAX]; +char NYMSECRING[PATHMAX]; +char NYMDB[PATHMAX]; +char STAREX[PATHMAX]; + +/** config ***************************************************************/ + +char MIXDIR[PATHMAX]; +char POOLDIR[PATHMAX]; + +/* programs */ +char SENDMAIL[LINELEN]; +char SENDANONMAIL[LINELEN]; +char NEWS[LINELEN]; +char TYPE1[LINELEN]; + +/* addresses */ +char MAILtoNEWS[LINELEN]; +char REMAILERNAME[LINELEN]; +char ANONNAME[LINELEN]; +char REMAILERADDR[LINELEN]; +char ANONADDR[LINELEN]; +char COMPLAINTS[LINELEN]; +int AUTOREPLY; +char SMTPRELAY[LINELEN]; +char SMTPUSERNAME[LINELEN]; +char SMTPPASSWORD[LINELEN]; + +#ifdef USE_SOCK +char HELONAME[LINELEN]; +char ENVFROM[LINELEN]; +int POP3DEL; +int POP3SIZELIMIT; +long POP3TIME; + +#endif /* USE_SOCK */ + +char SHORTNAME[LINELEN]; +char ALLPINGERSURL[BUFSIZE]; +char ALLPINGERSFILE[PATHMAX]; +char WGET[PATHMAX]; +char STATSSRC[PATHMAX]; +int STATSAUTOUPDATE; +long STATSINTERVAL; + + +/* remailer configuration */ +int REMAIL; +int MIX; +int PGP; +int UNENCRYPTED; +int REMIX; +int REPGP; +char EXTFLAGS[LINELEN]; /* user-defined capstring flags */ + +char PRECEDENCE[LINELEN]; /* default Precedence: header for outgoing mail */ +int POOLSIZE; +int RATE; +int INDUMMYP; +int OUTDUMMYP; +int INDUMMYMAXP; +int OUTDUMMYMAXP; +int MIDDLEMAN; +int AUTOBLOCK; +int STATSDETAILS; +char FORWARDTO[LINELEN]; +int SIZELIMIT; /* maximal size of remailed messages */ +int INFLATEMAX; /* maximal size of Inflate: padding */ +int MAXRANDHOPS; +int BINFILTER; /* filter binary attachments? */ +int LISTSUPPORTED; /* list supported remailers in remailer-conf reply? */ +long PACKETEXP; /* Expiration time for old packets */ +long IDEXP; /* 0 = no ID log !! */ +long SENDPOOLTIME; /* frequency for sending pool messages */ +long MAILINTIME; /* frequency for processing MAILIN mail */ + +long KEYLIFETIME; +long KEYOVERLAPPERIOD; +long KEYGRACEPERIOD; + +char ERRLOG[LINELEN]; +char ADDRESS[LINELEN]; +char NAME[LINELEN]; + +char ORGANIZATION[LINELEN]; +char MID[LINELEN]; + +/* client config */ +int NUMCOPIES; +char CHAIN[LINELEN]; +int VERBOSE; +int DISTANCE; +int MINREL; +int RELFINAL; +long MAXLAT; +long MINLAT; +char PGPPUBRING[PATHMAX]; +char PGPSECRING[PATHMAX]; +char PASSPHRASE[LINELEN]; +char MAILIN[PATHMAX]; +char MAILBOX[PATHMAX]; +char MAILABUSE[PATHMAX]; +char MAILBLOCK[PATHMAX]; +char MAILUSAGE[PATHMAX]; +char MAILANON[PATHMAX]; +char MAILERROR[PATHMAX]; +char MAILBOUNCE[PATHMAX]; + +int CLIENTAUTOFLUSH; +int MAXRECIPIENTS; + +long TIMESKEW_FORWARD; +long TIMESKEW_BACK; +int TEMP_FAIL; + +char ENTEREDPASSPHRASE[LINELEN] = ""; + +static int rereadconfig = 0; +static int terminatedaemon = 0; + +#if defined(S_IFDIR) && !defined(S_ISDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif /* defined(S_IFDIR) && !defined(S_ISDIR) */ + +static int mixdir(char *d, int create) +{ + int err; + struct stat buf; + + if (d != MIXDIR) + strncpy(MIXDIR, d, PATHMAX); + if (MIXDIR[strlen(MIXDIR) - 1] == DIRSEP) + MIXDIR[strlen(MIXDIR) - 1] = '\0'; + err = stat(MIXDIR, &buf); + if (err == -1) { + if (create) { +#ifndef POSIX + err = mkdir(MIXDIR); +#else /* end of not POSIX */ + err = mkdir(MIXDIR, S_IRWXU); +#endif /* else if POSIX */ + if (err == 0) + errlog(NOTICE, "Creating directory %s.\n", MIXDIR); + } else + err = 1; + } else if (!S_ISDIR(buf.st_mode)) + err = -1; + if (err == 0) + strcatn(MIXDIR, DIRSEPSTR, PATHMAX); + return (err); +} + +void whoami(char *addr, char *defaultname) +{ + char *p = NULL; + +#if defined(HAVE_GETDOMAINNAME) || (defined(HAVE_GETHOSTNAME) && ! defined(HAVE_UNAME)) + char line[LINELEN]; + +#endif /* defined(HAVE_GETDOMAINNAME) || [...] */ +#ifdef HAVE_UNAME + struct utsname uts; + +#endif /* HAVE_UNAME */ +#ifdef POSIX + p = getlogin(); +#endif /* POSIX */ + if (p == NULL) + strcpy(addr, defaultname); + else + strncpy(addr, p, LINELEN); + + strcatn(addr, "@", LINELEN); +#ifdef HAVE_UNAME + if (uname(&uts) != -1) + strcatn(addr, uts.nodename, LINELEN); +#elif defined(HAVE_GETHOSTNAME) /* end of HAVE_UNAME */ + if (gethostname(line, LINELEN) == 0) + strcatn(addr, line, LINELEN); +#endif /* defined(HAVE_GETHOSTNAME) */ + if (addr[strlen(addr) - 1] == '@') + strcatn(addr, SHORTNAME, LINELEN); + + if (strchr(strchr(addr, '@'), '.') == NULL) { +#ifdef HAVE_GETDOMAINNAME + if (getdomainname(line, LINELEN) == 0 && !streq(line, "(none)")) { + strcatn(addr, ".", LINELEN); + strcatn(addr, line, LINELEN); + } +#endif /* HAVE_GETDOMAINNAME */ + } +} + +#define read_conf(t) readconfline(line, #t, sizeof(#t)-1, t) + +static int readconfline(char *line, char *name, int namelen, char *var) +{ + if (strncmp(line, name, namelen) == 0 && + (isspace(line[namelen]) || line[namelen] == '=')) { + line += namelen; + if (*line == '=') + line++; + while (isspace(*line)) + line++; + if (line[0] == '\n' || line[0] == '\0') /* leave default */ + return (1); + strncpy(var, line, LINELEN); + if (var[strlen(var) - 1] == '\n') + var[strlen(var) - 1] = '\0'; + return (1); + } else + return (0); +} + +#define read_conf_i(t) readiconfline(line, #t, sizeof(#t)-1, &t) + +static int readiconfline(char *line, char *name, int namelen, int *var) +{ + if (strncmp(line, name, namelen) == 0 && + (isspace(line[namelen]) || line[namelen] == '=')) { + line += namelen; + if (*line == '=') + line++; + while (isspace(*line)) + line++; + if (line[0] == '\n' || line[0] == '\0') /* leave default */ + return (1); + switch (tolower(line[0])) { + case 'n': + *var = 0; + break; + case 'y': + *var = 1; + break; + case 'x': + *var = 2; + break; + default: + sscanf(line, "%d", var); + } + return (1); + } else + return (0); +} + +#define read_conf_t(t) readtconfline(line, #t, sizeof(#t)-1, &t) + +static int readtconfline(char *line, char *name, int namelen, long *var) +{ + char *linenext; + int mod = 0; + long l = 0; + long n; + + if (strncmp(line, name, namelen) == 0 && + (isspace(line[namelen]) || line[namelen] == '=')) { + line += namelen; + if (*line == '=') + line++; + for (;; line++) { + n = strtol(line, &linenext, 10); + if (linenext == line) + break; + line = linenext; + mod = 1; + assert(line != NULL); + while (isspace(*line)) + line++; + switch (tolower(*line)) { + case 'y': /* years */ + l += 365 * 24 * 60 * 60 * n; + break; + case 'b': /* months */ + l += 30 * 24 * 60 * 60 * n; + break; + case 'w': /* weeks */ + l += 7 * 24 * 60 * 60 * n; + break; + case 'd': /* days */ + l += 24 * 60 * 60 * n; + break; + case 's': /* seconds */ + l += n; + break; + case 'm': /* minutes */ + l += 60 * n; + break; + case 'h': /* hours - default */ + default: + l += 60 * 60 * n; + break; + } + } + if (mod) + *var = l; + return (1); + } else + return (0); +} + +static void mix_setdefaults() +{ +#define strnncpy(a,b) strncpy(a, b, sizeof(a)); a[sizeof(a)-1] = '\0' + + strnncpy(DISCLAIMFILE , DEFAULT_DISCLAIMFILE); + strnncpy(FROMDSCLFILE , DEFAULT_FROMDSCLFILE); + strnncpy(MSGFOOTERFILE, DEFAULT_MSGFOOTERFILE); + strnncpy(POP3CONF , DEFAULT_POP3CONF); + strnncpy(HELPFILE , DEFAULT_HELPFILE); + strnncpy(REQUESTDIR , DEFAULT_REQUESTDIR); + strnncpy(ABUSEFILE , DEFAULT_ABUSEFILE); + strnncpy(REPLYFILE , DEFAULT_REPLYFILE); + strnncpy(USAGEFILE , DEFAULT_USAGEFILE); + strnncpy(USAGELOG , DEFAULT_USAGELOG); + strnncpy(BLOCKFILE , DEFAULT_BLOCKFILE); + strnncpy(ADMKEYFILE , DEFAULT_ADMKEYFILE); + strnncpy(KEYFILE , DEFAULT_KEYFILE); + strnncpy(PGPKEY , DEFAULT_PGPKEY); + strnncpy(DSAPARAMS , DEFAULT_DSAPARAMS); + strnncpy(DHPARAMS , DEFAULT_DHPARAMS); + strnncpy(MIXRAND , DEFAULT_MIXRAND); + strnncpy(SECRING , DEFAULT_SECRING); + strnncpy(PUBRING , DEFAULT_PUBRING); + strnncpy(IDLOG , DEFAULT_IDLOG); + strnncpy(STATS , DEFAULT_STATS); + strnncpy(PGPMAXCOUNT , DEFAULT_PGPMAXCOUNT); + strnncpy(DESTBLOCK , DEFAULT_DESTBLOCK); + strnncpy(DESTALLOW , DEFAULT_DESTALLOW); + strnncpy(DESTALLOW2 , DEFAULT_DESTALLOW2); + strnncpy(SOURCEBLOCK , DEFAULT_SOURCEBLOCK); + strnncpy(HDRFILTER , DEFAULT_HDRFILTER); + strnncpy(REGULAR , DEFAULT_REGULAR); + strnncpy(POOL , DEFAULT_POOL); + strnncpy(TYPE1LIST , DEFAULT_TYPE1LIST); + strnncpy(TYPE2REL , DEFAULT_TYPE2REL); + strnncpy(PIDFILE , DEFAULT_PIDFILE); + + strnncpy(PGPREMPUBRING, DEFAULT_PGPREMPUBRING); + strnncpy(PGPREMPUBASC , DEFAULT_PGPREMPUBASC); + strnncpy(PGPREMSECRING, DEFAULT_PGPREMSECRING); + strnncpy(NYMSECRING , DEFAULT_NYMSECRING); + strnncpy(NYMDB , DEFAULT_NYMDB); + strnncpy(STAREX , DEFAULT_STAREX); + strnncpy(ALLPINGERSURL, DEFAULT_ALLPINGERSURL); + strnncpy(ALLPINGERSFILE, DEFAULT_ALLPINGERSFILE); + strnncpy(WGET , DEFAULT_WGET); + strnncpy(STATSSRC , DEFAULT_STATSSRC); + + strnncpy(MIXDIR , ""); + strnncpy(POOLDIR , ""); + +/* programs */ +#ifdef WIN32 + strnncpy(SENDMAIL , "outfile"); +#else /* end of WIN32 */ + strnncpy(SENDMAIL , "/usr/lib/sendmail -t"); +#endif /* else if not WIN32 */ + strnncpy(SENDANONMAIL , ""); + strnncpy(NEWS , ""); + strnncpy(TYPE1 , ""); + +/* addresses */ + strnncpy(MAILtoNEWS , "mail2news@dizum.com,mail2news@m2n.mixmin.net"); + strnncpy(REMAILERNAME , "Anonymous Remailer"); + strnncpy(ANONNAME , "Anonymous"); + strnncpy(REMAILERADDR , ""); + strnncpy(ANONADDR , ""); + strnncpy(COMPLAINTS , ""); + strnncpy(SMTPRELAY , ""); + AUTOREPLY = 0; + +#ifdef USE_SOCK + strnncpy(HELONAME , ""); + strnncpy(ENVFROM , ""); + POP3DEL = 0; + POP3SIZELIMIT = 0; + POP3TIME = 60 * 60; + +#endif /* USE_SOCK */ + + strnncpy(SHORTNAME , ""); + +/* configuration */ + REMAIL = 0; + MIX = 1; + PGP = 1; + UNENCRYPTED = 0; + REMIX = 1; + REPGP = 1; + STATSAUTOUPDATE = 0; + STATSINTERVAL = 8 * 60 * 60; + strnncpy(EXTFLAGS, ""); + + strnncpy(PRECEDENCE, ""); + POOLSIZE = 0; + RATE = 100; + INDUMMYP = 3; /* add dummy messages with probability p for each message added to the pool */ + OUTDUMMYP = 10; /* add dummy messages with probability p each time we send from the pool */ + INDUMMYMAXP = 84; /* for both of the above: while (rnd < p) { senddummy(); } */ + OUTDUMMYMAXP = 96; /* set max INDUMMYP and OUTDUMMYP such that 24 and 5.25 dummy messages will */ + MIDDLEMAN = 0; /* be generated on average. More than this is insane. */ + AUTOBLOCK = 1; + STATSDETAILS = 1; + strnncpy(FORWARDTO, "*"); + SIZELIMIT = 0; /* maximal size of remailed messages */ + INFLATEMAX = 50; /* maximal size of Inflate: padding */ + MAXRANDHOPS = 5; + BINFILTER = 0; /* filter binary attachments? */ + LISTSUPPORTED = 1; /* list supported remailers in remailer-conf reply? */ + PACKETEXP = 7 * SECONDSPERDAY; /* Expiration time for old packets */ + IDEXP = 7 * SECONDSPERDAY; /* 0 = no ID log !! */ + SENDPOOLTIME = 0; /* frequency for sending pool messages */ + MAILINTIME = 5 * 60; /* frequency for processing MAILIN mail */ + + KEYLIFETIME = 13 * 30 * 24 * 60 * 60; /* validity period for keys. */ + KEYOVERLAPPERIOD = 1 * 30 * 24 * 60 * 60; /* when keys have this amount of time */ + /* left before expiration, create */ + /* new ones when ./mix -K is run.*/ + KEYGRACEPERIOD = 7 * 24 * 60 * 60; /* accept mail to the old key for this */ + /* amount of time after it has expired. */ + + + strnncpy(ERRLOG , ""); + strnncpy(ADDRESS , ""); + strnncpy(NAME , ""); + + strnncpy(ORGANIZATION, "Anonymous Posting Service"); + strnncpy(MID , "y"); + +/* client config */ + NUMCOPIES = 1; + strnncpy(CHAIN, "*,*,*,*"); + VERBOSE = 2; + DISTANCE = 2; + MINREL = 98; + RELFINAL = 99; + MAXLAT = 36 * 60 * 60; + MINLAT = 5 * 60; + strnncpy(PGPPUBRING, ""); + strnncpy(PGPSECRING, ""); +#ifdef COMPILEDPASS + strnncpy(PASSPHRASE, COMPILEDPASS); +#else /* end of COMPILEDPASS */ + strnncpy(PASSPHRASE, ""); +#endif /* else if not COMPILEDPASS */ + strnncpy(MAILIN , ""); + strnncpy(MAILBOX , "mbox"); + strnncpy(MAILABUSE , ""); + strnncpy(MAILBLOCK , ""); +#ifdef WIN32 + strnncpy(MAILUSAGE , "nul:"); + strnncpy(MAILANON , "nul:"); + strnncpy(MAILERROR , "nul:"); +#else /* end of WIN32 */ + strnncpy(MAILUSAGE , "/dev/null"); + strnncpy(MAILANON , "/dev/null"); + strnncpy(MAILERROR , "/dev/null"); +#endif /* else if not WIN32 */ + strnncpy(MAILBOUNCE, ""); + + CLIENTAUTOFLUSH = 1; + MAXRECIPIENTS = 5; + + TIMESKEW_FORWARD = 2*7*24*60*60; + TIMESKEW_BACK = 12*60*60; + TEMP_FAIL = 75; +} + +int mix_configline(char *line) +{ + return (read_conf(ADDRESS) || read_conf(NAME) || + read_conf(SHORTNAME) || read_conf(REMAILERADDR) || + read_conf(ANONADDR) || read_conf(REMAILERNAME) || + read_conf(ANONNAME) || read_conf(COMPLAINTS) || + read_conf_i(AUTOREPLY) || read_conf(SMTPRELAY) || + read_conf(SMTPUSERNAME) || read_conf(SMTPPASSWORD) || +#ifdef USE_SOCK + read_conf(HELONAME) || read_conf(ENVFROM) || +#endif /* USE_SOCK */ + read_conf(SENDMAIL) || read_conf(SENDANONMAIL) || + read_conf(PRECEDENCE) || + read_conf_i(REMAIL) || read_conf_i(MIX) || + read_conf_i(PGP) || read_conf_i(UNENCRYPTED) || + read_conf_i(REMIX) || read_conf(NEWS) || + read_conf_i(REPGP) || read_conf(EXTFLAGS) || + read_conf(MAILtoNEWS) || read_conf(ERRLOG) || + read_conf(ORGANIZATION) || read_conf(MID) || + read_conf(TYPE1) || read_conf_i(POOLSIZE) || + read_conf_i(RATE) || read_conf_i(MIDDLEMAN) || + read_conf_i(INDUMMYP) || + read_conf_i(OUTDUMMYP) || + read_conf_i(AUTOBLOCK) || read_conf(FORWARDTO) || + read_conf_i(STATSDETAILS) || + read_conf_i(SIZELIMIT) || read_conf_i(INFLATEMAX) || + read_conf_i(MAXRANDHOPS) || read_conf_i(BINFILTER) || + read_conf_i(LISTSUPPORTED) || + read_conf_t(PACKETEXP) || read_conf_t(IDEXP) || + read_conf_t(SENDPOOLTIME) || read_conf_i(NUMCOPIES) || + read_conf_t(MAILINTIME) || + read_conf(CHAIN) || read_conf_i(VERBOSE) || + read_conf_i(DISTANCE) || read_conf_i(MINREL) || + read_conf_i(RELFINAL) || read_conf_t(MAXLAT) || + read_conf_t(MINLAT) || + read_conf(PGPPUBRING) || read_conf(PGPSECRING) || + read_conf(PASSPHRASE) || read_conf_t(KEYLIFETIME) || + read_conf_t(KEYGRACEPERIOD) || read_conf_t(KEYOVERLAPPERIOD) || +#ifdef USE_SOCK + read_conf_i(POP3DEL) || read_conf_i(POP3SIZELIMIT) || + read_conf_t(POP3TIME) || +#endif /* USE_SOCK */ + read_conf(MAILBOX) || read_conf(MAILABUSE) || + read_conf(MAILBLOCK) || read_conf(MAILUSAGE) || + read_conf(MAILANON) || read_conf(MAILERROR) || + read_conf(MAILBOUNCE) || read_conf(MAILIN) || + + read_conf(DISCLAIMFILE) || read_conf(FROMDSCLFILE) || + read_conf(MSGFOOTERFILE) || + read_conf(POP3CONF) || read_conf(HELPFILE) || + read_conf(REQUESTDIR) || + read_conf(ABUSEFILE) || read_conf(REPLYFILE) || + read_conf(USAGEFILE) || read_conf(USAGELOG) || + read_conf(BLOCKFILE) || read_conf(ADMKEYFILE) || + read_conf(KEYFILE) || read_conf(PGPKEY) || + read_conf(DSAPARAMS) || read_conf(DHPARAMS) || + read_conf(MIXRAND) || read_conf(SECRING) || + read_conf(PUBRING) || read_conf(IDLOG) || + read_conf(STATS) || read_conf(DESTBLOCK) || + read_conf(PGPMAXCOUNT) || + read_conf(DESTALLOW) || read_conf(DESTALLOW2) || + read_conf(SOURCEBLOCK) || + read_conf(STAREX) || read_conf(ALLPINGERSURL) || + read_conf(ALLPINGERSFILE) || + read_conf(HDRFILTER) || read_conf(REGULAR) || + read_conf(POOL) || read_conf(TYPE1LIST) || + read_conf(TYPE2REL) || + read_conf(PGPREMPUBRING) || read_conf(PGPREMPUBASC) || + read_conf(PGPREMSECRING) || read_conf(NYMSECRING) || + read_conf(NYMDB) || read_conf(PIDFILE) || + read_conf(WGET) || read_conf(STATSSRC) || + read_conf_i(STATSAUTOUPDATE) || read_conf_t(STATSINTERVAL) || + + read_conf_i(CLIENTAUTOFLUSH) || + read_conf_i(MAXRECIPIENTS) || + + read_conf_t(TIMESKEW_FORWARD) || + read_conf_t(TIMESKEW_BACK) || + read_conf_i(TEMP_FAIL) ); +} + +int mix_config(void) +{ + char *d; + FILE *f; + char line[PATHMAX]; + int err = -1; +#ifdef POSIX + struct passwd *pw; +#endif /* POSIX */ + struct stat buf; +#ifdef HAVE_UNAME + struct utsname uts; +#endif /* HAVE_UNAME */ +#ifdef WIN32 + HKEY regsw, reg, regpgp; + DWORD type, len; + int rkey = 0; +#endif /* WIN32 */ + + mix_setdefaults(); + +#ifdef POSIX + pw = getpwuid(getuid()); +#endif /* POSIX */ + + /* find our base directory + * + * first match wins. + * + * - what the MIXPATH environment variable points to, if it is set. + * - On WIN32, HKEY_CURRENT_USER\Software\Mixmaster\MixDir, if it exists + * - whatever is compiled in with -DSPOOL + * - On Win32 %APPDATA%\Mixmaster + * - on POSIX, ~/Mix (or ~/<HOMEMIXDIR>) + * - the current working directory + */ + + if (err == -1 && (d = getenv("MIXPATH")) != NULL) + err = mixdir(d, 1); + +#ifdef WIN32 + RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &regsw); + len=sizeof(line); + if (err == -1 && + RegOpenKeyEx(regsw, "Mixmaster", 0, KEY_QUERY_VALUE, &reg) == 0) { + if (RegQueryValueEx(reg, "MixDir", 0, &type, line, &len) == 0) + err = mixdir(line, 1); + RegCloseKey(reg); + } +#endif /* WIN32 */ + +#ifdef SPOOL + if (err == -1 && strlen(SPOOL) > 0) + err = mixdir(SPOOL, 0); +#endif /* SPOOL */ + +#ifdef WIN32 + if (err == -1) { + LPMALLOC lpmalloc; + ITEMIDLIST *itemidlist; + if (SUCCEEDED(SHGetMalloc(&lpmalloc))) + { + SHGetSpecialFolderLocation(0,CSIDL_APPDATA,&itemidlist); + SHGetPathFromIDList(itemidlist,line); + lpmalloc->lpVtbl->Free(lpmalloc,&itemidlist); + lpmalloc->lpVtbl->Release(lpmalloc); + + strcatn(line, "\\Mixmaster", PATHMAX); + err = mixdir(line, 1); + + } + } +#endif /* WIN32 */ + +#ifdef POSIX + if (err == -1 && pw != NULL) { + strncpy(line, pw->pw_dir, PATHMAX); + line[PATHMAX-1] = '\0'; + if (line[strlen(line) - 1] != DIRSEP) + strcatn(line, DIRSEPSTR, PATHMAX); + strcatn(line, HOMEMIXDIR, PATHMAX); + err = mixdir(line, 1); + } +#endif /* POSIX */ + + if (err == -1) { + getcwd(MIXDIR, PATHMAX); + mixdir(MIXDIR, 0); + } + +#ifdef GLOBALMIXCONF + f = mix_openfile(GLOBALMIXCONF, "r"); + if (f != NULL) { + while (fgets(line, LINELEN, f) != NULL) + if (line[0] > ' ' && line[0] != '#') + mix_configline(line); + fclose(f); + } +#endif /* GLOBALMIXCONF */ + f = mix_openfile(MIXCONF, "r"); + if (f != NULL) { + while (fgets(line, LINELEN, f) != NULL) + if (line[0] > ' ' && line[0] != '#') + mix_configline(line); + fclose(f); + } + + mixfile(POOLDIR, POOL); /* set POOLDIR after reading POOL from cfg file */ + if (POOLDIR[strlen(POOLDIR) - 1] == DIRSEP) + POOLDIR[strlen(POOLDIR) - 1] = '\0'; + if (stat(POOLDIR, &buf) != 0) + if +#ifndef POSIX + (mkdir(POOLDIR) != 0) +#else /* end of not POSIX */ + (mkdir(POOLDIR, S_IRWXU) == -1) +#endif /* else if POSIX */ + strncpy(POOLDIR, MIXDIR, PATHMAX); + + if (IDEXP > 0 && IDEXP < 5 * SECONDSPERDAY) + IDEXP = 5 * SECONDSPERDAY; + if (MAXRANDHOPS > 20) + MAXRANDHOPS = 20; + if (INDUMMYP > INDUMMYMAXP) + INDUMMYP = INDUMMYMAXP; + if (OUTDUMMYP > OUTDUMMYMAXP) + OUTDUMMYP = OUTDUMMYMAXP; + + if (strchr(SHORTNAME, '.')) + *strchr(SHORTNAME, '.') = '\0'; + if (strchr(SHORTNAME, ' ')) + *strchr(SHORTNAME, ' ') = '\0'; +#ifdef HAVE_UNAME + if (SHORTNAME[0] == '\0' && uname(&uts) != -1) + strncpy(SHORTNAME, uts.nodename, LINELEN); +#elif defined(HAVE_GETHOSTNAME) /* end of HAVE_UNAME */ + if (SHORTNAME[0] == '\0') + gethostname(SHORTNAME, LINELEN); +#endif /* defined(HAVE_GETHOSTNAME) */ + if (SHORTNAME[0] == '\0') + strcpy(SHORTNAME, "unknown"); + + if (ADDRESS[0] == '\0') + whoami(ADDRESS, "user"); + +#ifdef HAVE_GECOS + if (NAME[0] == '\0' && pw != NULL) + strcatn(NAME, pw->pw_gecos, sizeof(NAME)); +#endif /* HAVE_GECOS */ + + if (REMAILERADDR[0] == '\0') + strncpy(REMAILERADDR, ADDRESS, LINELEN); + + if (COMPLAINTS[0] == '\0') + strncpy(COMPLAINTS, REMAILERADDR, LINELEN); + + if (strchr(REMAILERNAME, '@') == NULL) { + strcatn(REMAILERNAME, " <", LINELEN); + strcatn(REMAILERNAME, REMAILERADDR, LINELEN); + strcatn(REMAILERNAME, ">", LINELEN); + } + if (strchr(ANONNAME, '@') == NULL && ANONADDR[0] != '\0') { + strcatn(ANONNAME, " <", LINELEN); + strcatn(ANONNAME, ANONADDR, LINELEN); + strcatn(ANONNAME, ">", LINELEN); + } + if (strchr(ANONNAME, '@') == NULL) { + strcatn(ANONNAME, " <", LINELEN); + strcatn(ANONNAME, REMAILERADDR, LINELEN); + strcatn(ANONNAME, ">", LINELEN); + } +#ifndef USE_PGP + if (TYPE1[0] == '\0') + PGP = 0; +#endif /* not USE_PGP */ + +#ifdef WIN32 + if (RegOpenKeyEx(regsw, "PGP", 0, KEY_ALL_ACCESS, &regpgp) == 0) + rkey++; + if (rkey && RegOpenKeyEx(regpgp, "PGPlib", 0, KEY_QUERY_VALUE, &reg) == 0) + rkey++; + if (PGPPUBRING[0] == '\0' && rkey == 2) { + len = PATHMAX; + RegQueryValueEx(reg, "PubRing", 0, &type, PGPPUBRING, &len); + } + if (PGPSECRING[0] == '\0' && rkey == 2) { + len = PATHMAX; + RegQueryValueEx(reg, "SecRing", 0, &type, PGPSECRING, &len); + } + if (rkey == 2) + RegCloseKey(reg); + if (rkey) + RegCloseKey(regpgp); + RegCloseKey(regsw); +#endif /* WIN32 */ + + if (PGPPUBRING[0] == '\0') { + char *d; + + if ((d = getenv("HOME")) != NULL) { + strcpy(PGPPUBRING, d); + strcatn(PGPPUBRING, "/.pgp/", PATHMAX); + } + strcatn(PGPPUBRING, "pubring.pkr", PATHMAX); + if (stat(PGPPUBRING, &buf) == -1) + strcpy(strrchr(PGPPUBRING, '.'), ".pgp"); + } + if (PGPSECRING[0] == '\0') { + char *d; + + if ((d = getenv("HOME")) != NULL) { + strcpy(PGPSECRING, d); + strcatn(PGPSECRING, "/.pgp/", PATHMAX); + } + strcatn(PGPSECRING, "secring.skr", PATHMAX); + if (stat(PGPSECRING, &buf) == -1) + strcpy(strrchr(PGPSECRING, '.'), ".pgp"); + } + if (streq(NEWS, "mail-to-news")) + strncpy(NEWS, MAILtoNEWS, sizeof(NEWS)); + + if (f == NULL) { +#ifndef GLOBALMIXCONF + /* Only write the config file in non systemwide installation */ + f = mix_openfile(MIXCONF, "w"); + if (f == NULL) + errlog(WARNING, "Can't open %s%s!\n", MIXDIR, MIXCONF); + else { + fprintf(f, "# mix.cfg - mixmaster configuration file\n"); + fprintf(f, "NAME %s\n", NAME); + fprintf(f, "ADDRESS %s\n", ADDRESS); + fprintf(f, "\n# edit to set up a remailer:\n"); + fprintf(f, "REMAIL n\n"); + fprintf(f, "SHORTNAME %s\n", SHORTNAME); + fprintf(f, "REMAILERADDR %s\n", REMAILERADDR); + fprintf(f, "COMPLAINTS %s\n", COMPLAINTS); + fclose(f); + } +#endif /* not GLOBALMIXCONF */ + REMAIL = 0; + } + + if (ENTEREDPASSPHRASE[0] != '\0') { + strncpy(PASSPHRASE, ENTEREDPASSPHRASE, LINELEN); + PASSPHRASE[LINELEN-1] = 0; + }; + + return (0); +} + +/** Library initialization: ******************************************/ + +static int initialized = 0; + +void mix_check_timeskew() { + FILE *f; + long now, tpool = 0, tpop3 = 0, tdaily = 0, tmailin = 0, latest = 0; + + f = mix_openfile(REGULAR, "r+"); + if (f != NULL) { + lock(f); + fscanf(f, "%ld %ld %ld %ld", &tpool, &tpop3, &tdaily, &tmailin); + latest = tpool; + latest = latest > tpop3 ? latest : tpop3; + latest = latest > tdaily ? latest : tdaily; + latest = latest > tmailin ? latest : tmailin; + now = time(NULL); + + + if (( (TIMESKEW_BACK != 0) && (now < latest - TIMESKEW_BACK )) || + ( (TIMESKEW_FORWARD != 0) && (now > latest + TIMESKEW_FORWARD)) ) { + /* Possible timeskew */ + errlog(ERRORMSG, "Possible timeskew detected. Check clock and rm %s\n", REGULAR); + exit(TEMP_FAIL); + } + fclose(f); + } else { + /* shrug */ + } +} + +int mix_init(char *mixdir) +{ + if (!initialized) { + if (mixdir) + strncpy(MIXDIR, mixdir, LINELEN); + mix_config(); +#if defined(USE_SOCK) && defined(WIN32) + sock_init(); +#endif /* defined(USE_SOCK) && defined(WIN32) */ + /* atexit (mix_exit); */ + initialized = 1; + } + + if (rnd_init() == -1) + rnd_seed(); + return(0); +} + +void mix_exit(void) +{ + if (!initialized) + return; + rnd_final(); +#if defined(USE_SOCK) && defined(WIN32) + sock_exit(); +#endif /* defined(USE_SOCK) && defined(WIN32) */ + initialized=0; +} + +void mix_upd_stats(void) +{ + FILE *f; + BUFFER *statssrc; + statssrc = buf_new(); + buf_clear(statssrc); + f = mix_openfile(STATSSRC, "r"); + if (f != NULL) { + buf_read(statssrc, f); + fclose(f); + } + if (statssrc->length > 0) + download_stats(statssrc->data); + buf_free(statssrc); +} + +int mix_regular(int force) +{ + FILE *f; + long now, tpool = 0, tpop3 = 0, tdaily = 0, tmailin = 0, tstats = 0; + int ret = 0; + + mix_init(NULL); + now = time(NULL); + + f = mix_openfile(REGULAR, "r+"); + if (f != NULL) { + lock(f); + fscanf(f, "%ld %ld %ld %ld %ld", &tpool, &tpop3, &tdaily, &tmailin, &tstats); + if (now - tpool >= SENDPOOLTIME) + force |= FORCE_POOL | FORCE_MAILIN; +#ifdef USE_SOCK + if (now - tpop3 >= POP3TIME) + force |= FORCE_POP3 | FORCE_MAILIN; +#endif /* USE_SOCK */ + if (now - tdaily >= SECONDSPERDAY) + force |= FORCE_DAILY; + if (now - tmailin >= MAILINTIME) + force |= FORCE_MAILIN; + if (now - tstats >= STATSINTERVAL) + force |= FORCE_STATS; + if (force & FORCE_POOL) + tpool = now; + if (force & FORCE_POP3) + tpop3 = now; + if (force & FORCE_DAILY) + tdaily = now; + if (force & FORCE_MAILIN) + tmailin = now; + if (force & FORCE_STATS) + tstats = now; + rewind(f); + fprintf(f, "%ld %ld %ld %ld %ld\n", tpool, tpop3, tdaily, tmailin, tstats); + unlock(f); + fclose(f); + } else { + force = FORCE_POOL | FORCE_POP3 | FORCE_DAILY | FORCE_MAILIN | FORCE_STATS; + f = mix_openfile(REGULAR, "w+"); + if (f != NULL) { + lock(f); + fprintf(f, "%ld %ld %ld %ld %ld\n", now, now, now, now, now); + unlock(f); + fclose(f); + } else + errlog(ERRORMSG, "Can't create %s!\n", REGULAR); + } + + if (force & FORCE_DAILY) + mix_daily(), ret = 1; +#ifdef USE_SOCK + if (force & FORCE_POP3) + pop3get(); +#endif /* USE_SOCK */ + if (force & FORCE_MAILIN) + ret = process_mailin(); + if (force & FORCE_POOL) + ret = pool_send(); + if ((force & FORCE_STATS) && (STATSAUTOUPDATE != 0)) + mix_upd_stats(); + + return (ret); +} + +int mix_daily(void) +{ + idexp(); + pgpmaxexp(); + pool_packetexp(); + stats(NULL); + keymgt(0); + return (0); +} + +/** Handle signals SIGHUP, SIGINT, and SIGTERM + This signal handler gets called if the daemon + process receives one of SIGHUP, SIGINT, or SIGTERM. + It then sets either rereadconfig of terminatedaemon + to true depending on the signal received. + + @author PP + @return nothing + */ +#ifdef POSIX +void sighandler(int signal) { + if (signal == SIGHUP) + rereadconfig = 1; + else if (signal == SIGINT || signal == SIGTERM) + terminatedaemon = 1; +}; +#endif /* POSIX */ + +/** Set the signal handler for SIGHUP, SIGINT and SIGTERM + This function registers signal handlers so that + we can react on signals send by the user in daemon + mode. SIGHUP will instruct mixmaster to reload its + configuration while SIGINT and SIGTERM will instruct + it to shut down. Mixmaster will finish the current + pool run before it terminates. + + @param restart Whether or not system calls should be + restarted. Usually we want this, the + only excetion is the sleep() in the + daemon mail loop. + @author PP + @return -1 if calling sigaction failed, 0 on + no error + */ +int setsignalhandler(int restart) +{ +#ifdef POSIX + struct sigaction hdl; + int err = 0; + + memset(&hdl, 0, sizeof(hdl)); + hdl.sa_handler = sighandler; + hdl.sa_flags = restart ? SA_RESTART : 0; + + if (sigaction(SIGHUP, &hdl, NULL)) + err = -1; + if (sigaction(SIGINT, &hdl, NULL)) + err = -1; + if (sigaction(SIGTERM, &hdl, NULL)) + err = -1; + return (err); +#else /* POSIX */ + return(0); +#endif /* POSIX */ +} + +#ifdef WIN32 +/* Try to detect if we are the service or not... + seems there is no easy reliable way */ +int is_nt_service(void) +{ + static int issvc = -1; +#ifdef WIN32SERVICE + STARTUPINFO StartupInfo; + OSVERSIONINFO VersionInfo; + DWORD dwsize; + + if (issvc != -1) /* do it only once */ + return issvc; + + VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); + if (GetVersionEx(&VersionInfo)) + if (VersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) + return issvc = 0; /* not NT - not the service */ + + GetStartupInfo(&StartupInfo); + if (StartupInfo.lpDesktop[0] == 0) + return issvc = 1; /* have no desktop - we are the service probably */ +#endif /* WIN32SERVICE */ + + return issvc = 0; /* assume not the service */ +} /* is_nt_service */ + +HANDLE hMustTerminate = NULL; +void set_nt_exit_event(HANDLE h_svc_exit_event) +{ + hMustTerminate = h_svc_exit_event; +} /* set_nt_exit_event */ + +#endif /* WIN32 */ + +int mix_daemon(void) +{ + long t, slept; + t = SENDPOOLTIME; + if (MAILINTIME < t && (MAILIN != NULL && MAILIN[0] != '\0')) + t = MAILINTIME; +#ifdef USE_SOCK + if (POP3TIME < t) + t = POP3TIME; +#endif /* USE_SOCK */ + if (t < 5) + t = 5; /* Some kind of safety for broken systems */ + slept = t; + + setsignalhandler(1); /* set signal handlers and restart any interrupted system calls */ + for(;;) { + if (terminatedaemon) + break; + if (rereadconfig) { + rereadconfig = 0; + mix_config(); + t = SENDPOOLTIME; + if (MAILINTIME < t && (MAILIN != NULL && MAILIN[0] != '\0')) + t = MAILINTIME; +#ifdef USE_SOCK + if (POP3TIME < t) + t = POP3TIME; + if (t < 5) + t = 5; /* Some kind of safety for broken systems */ +#endif /* USE_SOCK */ + } + if (slept >= t) { + mix_regular(0); + slept = 0; + } + +#ifdef WIN32SERVICE + if (hMustTerminate) { + if (WaitForSingleObject(hMustTerminate, t * 1000) == WAIT_OBJECT_0) { + CloseHandle(hMustTerminate); + terminatedaemon = 1; + } + } +#endif /* WIN32SERVICE */ + + if (!terminatedaemon && !rereadconfig) { + setsignalhandler(0); /* set signal handlers; don't restart system calls */ +#ifdef WIN32 + sleep(t); /* how to get the real number of seconds slept? */ + slept = t; +#else /* end of WIN32 */ + slept += (t - slept) - sleep(t - slept); +#endif /* else if not WIN32 */ + setsignalhandler(1); /* set signal handlers and restart any interrupted system calls */ + } + } + return (0); +} + +/** error ***************************************************************/ + +void errlog(int type, char *fmt,...) +{ + va_list args; + BUFFER *msg; + FILE *e = NULL; + time_t t; + struct tm *tc; + char line[LINELEN]; + int p; + char err[6][8] = + {"", "Error", "Warning", "Notice", "Info", "Info"}; + + if ((VERBOSE == 0 && type != ERRORMSG) || (type == LOG && VERBOSE < 2) + || (type == DEBUGINFO && VERBOSE < 3)) + return; + + t = time(NULL); + tc = localtime(&t); + strftime(line, LINELEN, "[%Y-%m-%d %H:%M:%S] ", tc); + + msg = buf_new(); + buf_appends(msg, line); + p = msg->length; + buf_appendf(msg, "%s: ", err[type]); + va_start(args, fmt); + buf_vappendf(msg, fmt, args); + va_end(args); + + if (streq(ERRLOG, "stdout")) + e = stdout; + else if (streq(ERRLOG, "stderr")) + e = stderr; + + if (e == NULL && (ERRLOG[0] == '\0' || + (e = mix_openfile(ERRLOG, "a")) == NULL)) + mix_status("%s", msg->data + p); + else { + buf_write(msg, e); + if (e != stderr && e != stdout) { + fclose(e); + /* duplicate the error message on screen */ + mix_status("%s", msg->data + p); + } + } + buf_free(msg); +} + +static char statusline[BUFSIZE] = ""; + +void mix_status(char *fmt,...) +{ + va_list args; + + if (fmt != NULL) { + va_start(args, fmt); +#ifdef _MSC + _vsnprintf(statusline, sizeof(statusline) - 1, fmt, args); +#else /* end of _MSC */ + vsnprintf(statusline, sizeof(statusline) - 1, fmt, args); +#endif /* else if not _MSC */ + va_end(args); + } +#ifdef USE_NCURSES + if (menu_initialized) { + cl(LINES - 2, 10); + printw("%s", statusline); + refresh(); + } else +#endif /* USE_NCURSES */ + { + fprintf(stderr, "%s", statusline); + } +} + +void mix_genericerror(void) +{ + if (streq(statusline, "") || strfind(statusline, "...") || + strifind(statusline, "generating")) + mix_status("Failed!"); + else + mix_status(NULL); +} diff --git a/Src/mix.h b/Src/mix.h @@ -0,0 +1,917 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + + Mixmaster Library API + ===================== + +The Mixmaster library consists of a set of high-level functions that +generate or process remailer messages, lower-level functions that +manipulate data in various ways, and a number of functions that +provide an interface to the underlying cryptographic library. +Generally, a return value of 0 indicates success, and -1 an error. + + +Initialization +============== + +int mix_init(char mixdir[]); + + This function initializes internal data of the Mixmaster library, + such as the random number generator. This should be the first call + to the Mixmaster library. It returns 0 on success. If the random + number generator cannot be initialized, mix_init() terminates. + + The variable mixdir determines where the Mixmaster configuration + files and the message pool are located. If mixdir is NULL, the + library will use the directory specified in the environment variable + $MIXPATH, the directory given at compile time if it exists, and the + directory ~/Mix otherwise. + + +void mix_exit(void); + + A program must call mix_exit before exiting. This function writes back + the state of the random number generator. + + +Using the Mixmaster DLL +======================= + +In textmode applications, mix_init() can be used as described above. +In graphical applications, these functions are not needed. Instead, +the function rnd_mouse() should be called whenever the program gets +WM_MOUSEMOVE or other messages: + +int rnd_mouse(UINT i, WPARAM w, LPARAM l); + + All events that a window gets may be passed to this function. It + will extract the inherent randomness in user interaction, especially + in mouse movements. It returns 100 if it has accumulated enough + randomness to perform cryptographic operations, and a number between + 0 and 99 otherwise. This number can be used to provide graphical + feedback on the progress of initializing the random number generator + while asking the user to move the mouse. A runtime error will occur + if any cryptographic functions are used before rnd_mouse() has + signaled success. + + +Message I/O +=========== + +The library uses dynamically allocated buffers for messages and other +data. Functions for buffer manipulation are described in section +"Buffers" below. + + +BUFFER *buf_new(void); + + Buffers must be initialized before they can be used. buf_new() returns + a pointer to a newly initialized buffer. + + +int buf_free(BUFFER *buf); + + When a buffer is no longer needed, it should be freed. This function + returns the memory used for the buffer to the operating system. + + +int buf_read(BUFFER *message, FILE *infile); + + This function reads data from a stream and appends them to the buffer. + + Return values: + 0 on success, + 1 if the file is too large to store it in a buffer, + -1 if no data could be read. + + +int buf_write(BUFFER *message, FILE *outfile); + + This function writes the entire buffer to the output stream. + + Return values: + 0 if the buffer could be written completely, + -1 otherwise. + +int buf_write_sync(BUFFER *message, FILE *outfile); + + This function does the same as buf_write but also does + checks for return values of fflush, fsync and ***fclose***. + + Return values: + 0 if the buffer could be written, synced and closed completely, + -1 otherwise. + +Remailer Messages +================= + +int mix_encrypt(int type, BUFFER *message, char *chain, int numcopies, + BUFFER *feedback); + + This function creates a Mixmaster message and stores it the Mixmaster + message pool. + + The type is one of the following: + + MSG_MAIL electronic mail message + MSG_POST Usenet news article + MSG_NULL dummy message, will be discarded + + *chain is a string consisting of a comma-separated list of remailer + names that the message will be sent through. '*' means that a remailer + will be chosen at random. If *chain is NULL, mix_encrypt() will use the + default chain. + + numcopies is a number between 1 and 10 that indicates how many + (redundant) copies of the message should be sent. If numcopies is 0, + the default value will be used. The default values for *chain and + numcopies are read from the configuration file. + + If *feedback is not NULL, mix_encrypt() will write the chain(s) that + have been selected as newline-separated strings, or a textual error + message to *feedback. This text can be presented to the user as + feedback. + + Return values: + 0 on success, + -1 if the message could not be created. + + +int mix_decrypt(BUFFER *message); + + This is the remailer function, which reads Mixmaster and Cypherpunk + remailer messages as well as help file and key requests. Remailer + messages are decrypted and stored in the message pool. Replies to + information requests are sent immediately. + + Return values: + 0 if the message has been processed successfully, + 1 if the message is of an unknown type, + -1 if the message could not be processed. + + +int mix_send(void); + + This function causes the messages in the pool to be sent. Depending on + the configuration, mix_send() may send only a certain fraction of the + messages in the pool. + + Return value: The size of the pool after the messages have been sent. + + +int mix_regular(int force); + + This function is responsible for regular actions of the remailer such + as sending messages from the pool, getting mail from POP3 servers and + expiring log files. + + +Nymserver Client Functions +========================== + +The nymserver functions use user_pass() to get the passphrase for +opening the nym database. + +int nym_config(int mode, char *nym, char *nymserver, BUFFER *pseudonym, + char *sendchain, int sendnumcopies, BUFFER *chains, + BUFFER *options); + + Create, modify or delete a nym. mode is one of NYM_CREATE, NYM_MODIFY and + NYM_DELETE. + + nym is the pseudonymous address or its local part. In the latter case, + nymserver must contain a string that selects a nymserver. + + pseudonym is a text string or NULL. + + sendchain and sendnumcopies are the chain and number of copies of + the Mixmaster message sent to the nymserver. + + chains contains a list of reply blocks, consisting of "To:", + "Newsgroups:", "Null:", "Latency:", "Chain:" and arbitrary header lines + such as "Subject:". The "Chain:" line contains a remailer selection + string for type 1 remailers. The reply blocks are separated by empty + lines. + + options contains nymserver options (any of "acksend", "signsend", + "fixedsize", "disable", "fingerkey" with a "+" or "-" prefix) or is NULL. + + +int nym_encrypt(BUFFER *msg, char *nym, int type); + + Prepare the message msg of type MSG_MAIL or MSG_POST to be sent using + the nym. After successful encryption, msg contains a message of type + MSG_MAIL addressed to the nymserver. + + +int nym_decrypt(BUFFER *msg, char *nym, BUFFER *log); + + Decrypt nymserver replies and PGP messages. If msg contains a nymserver + reply, the the recipient nym is stored in nym (unless nym is NULL), and + msg is replaced with the plaintext message in the Unix mail folder + format. + + If log is not NULL, nym_decrypt will compute a unique ID for each + message and append it to log. If the ID already is contained in log, + it will return an empty msg buffer. + + +Lower-Level Remailer Functions +============================== + +t1_decrypt(BUFFER *in); + + Decrypts and processes a Cypherpunk remailer message. + + +t2_decrypt(BUFFER *in); + + Decrypts and processes a Mixmaster remailer message. + + +int mix_pool(BUFFER *msg, int type, long latent); + + Adds the message msg of type MSG_MAIL or MSG_POST to the pool. + latent is 0 or the message latency in seconds. + + +OpenPGP encryption +================== + +int pgp_encrypt(int mode, BUFFER *message, BUFFER *encr, + BUFFER *sigid, BUFFER *pass, char *pubring, + char *secring); + + This function encrypts and signs a message according to OpenPGP (RFC 2440). + + mode is the bitwise or of one of PGP_ENCRYPT, PGP_CONVENTIONAL and PGP_SIGN, + and any of PGP_TEXT, PGP_REMAIL and PGP_NOARMOR. + + PGP_CONVENTIONAL: the message is encrypted conventionally, using + the passphrase encr. If PGP_NCONVENTIONAL is used instead, + the new OpenPGP format is used. + PGP_ENCRYPT: public key encryption is used. The message is encrypted to + the first public key on the keyring a User ID of which contains + the substring encr. encr may contain several lines with one + address substring each. + PGP_SIGN: the message is signed with the first key from the secret + key ring whose user ID contains sigid as a substring, or the + first key if sigid is NULL. + PGP_TEXT: message is treated as text, without PGP_TEXT as binary. + PGP_DETACHEDSIG: signature will not include the signed message. + PGP_REMAIL: a random offset is subtracted from signature dates, and the + ASCII armor is made to mimic PGP. + PGP_NOARMOR: message armor is not applied. + + If none of PGP_SIGN, PGP_CONVENTIONAL and PGP_ENCRYPT is set, the + message is only compressed and armored. + + pubring and secring can be NULL or specify the name of a key ring. + + Return values: + 0 on success, + -1 no matching key found, + PGP_PASS bad signature passphrase. + + +int pgp_mailenc(int mode, BUFFER *message, char *sigid, + BUFFER *pass, char *pubring, char *secring); + + This function encrypts and signs an RFC 822 e-mail message according to + RFC 2015 (OpenPGP/MIME). Signatures without encryption on non-MIME messages + are "cleartext" signatures. + + +int pgp_decrypt(BUFFER *message, BUFFER *pass, BUFFER *sig, char *pubring, + char *secring); + + This function decrypts the OpenPGP message and verifies its signature. + pass must contain the passphrase if message is conventionally encrypted + or the secret key is protected by a passphrase. Otherwise it can be + NULL. + + If message is a detached signature, sig must contain the signed data. + It sig is NULL, the message will be decrypted without signature + verification. + + pgp_getmsg() writes a string containing the signing time and + signer's user ID or the key ID of the unknown signature key to sig. + + pubring and secring can be NULL or specify the name of a key ring. + + Return values: + PGP_OK on success, + PGP_ERR the message can't be read, + PGP_PASS bad passphrase, + PGP_NOMSG message is not an OpenPGP message, + PGP_SIGOK success, and signature has been verified, + PGP_SIGNKEY can't verify signature, + PGP_SIGBAD bad signature, + PGP_NODATA OpenPGP message does not contain user data. + + +int pgp_keygen(int algo, int bits, BUFFER *userid, BUFFER *pass, char *pubring, + char *secring, int remail); + + Generate a new key pair with given userid, encrypt the secret key with + pass if not NULL. Use a fake date if remail is not zero. Assume an + encrypted secring if remail == 2. algo is PGP_ES_RSA or PGP_E_ELG. + + +Buffers +======= + +Buffers contain binary data of arbitrary length. You can append data +to buffers, clear buffers, and read data from buffers sequentially. +As data are appended to a buffer, memory is allocated dynamically. + +typedef unsigned char byte; + +typedef struct +{ + byte *data; + long length; + long ptr; + long size; + byte sensitive; +} BUFFER; + +For a buffer *b, b->data is a pointer to at least b->length+1 bytes of +memory. b->data[b->length] is guaranteed to contain a null byte, so that +string functions can be used directly on buffers that contain text. + +ptr is a counter for reading data from the buffer. b->data[b->ptr] is +the first data byte that has not been read (0 <= ptr <= length). + +If sensitive is 1, the buffer contents will be overwritten before the +memory is released. + + +int buf_reset(BUFFER *buf); + + This function empties the buffer and returns the memory it has used to + the operating system. It does not free the buffer itself. + + +int buf_clear(BUFFER *buf); + + buf_clear() empties the buffer but does not free the memory it uses. + This function should be used if data of a similar size will be stored + to the buffer later. + + +int buf_eq(BUFFER *buf1, BUFFER *buf2); + + Return values: + 1 if the buffers contain identical data, + 0 otherwise. + + +int buf_append(BUFFER *buf, byte *msg, int len); + + This is the most basic function for appending data to a buffer. It is + called by all other functions that write to buffers. buf_append() + appends len bytes pointed to by msg to buf. New memory will be + allocated for the buffer if necessary. + + If msg is NULL, the buffer is increased by len bytes, but no + guarantee is made about the contents of the appended bytes. + + Return value: + 0 on success, + does not return if allocation of memory fails. + + +int buf_appendc(BUFFER *buf, byte b); + appends the byte b to buf. + + +int buf_appends(BUFFER *buf, char *s); + appends the null-terminated string s to buf. + + +int buf_appendf(BUFFER *buf, char *fmt, ...); + appends formatted output to buf. + + +int buf_sets(BUFFER *buf, char *s); + sets buf to contain the null-terminated string s. + + +int buf_setf(BUFFER *buf, char *fmt, ...); + sets buf to contain the formatted output. + + +int buf_nl(BUFFER *buf); + appends a newline character to buf. + + +int buf_cat(BUFFER *buf, BUFFER *f); + appends the entire contents of f to buf. + + +int buf_rest(BUFFER *buf, BUFFER *f); + appends the unread data from f to buf. + + +int buf_set(BUFFER *buf, BUFFER *f); + sets buf to a copy of the contents of f. + + +int buf_move(BUFFER *buf, BUFFER *f); + sets buf to the contents of f, and resets f. This is equivalent to + buf_set(buf, f); buf_reset(f); but more efficient. + + +int buf_appendrnd(BUFFER *buf, int n); + appends n cryptographically strong pseudo-random bytes to buf. + + +int buf_setrnd(BUFFER *buf, int n); + places n cryptographically strong pseudo-random bytes in buf. + + +int buf_appendzero(BUFFER *buf, int n); + appends n null bytes to buf. + + +int buf_pad(BUFFER *buf, int size); + pads the buffer with cryptographically strong pseudo-random data to + length size. Aborts if size < buf->length. + + +int buf_appendi(BUFFER *b, int i); + appends the two bytes representing i in big-endian byte order to buf. + + +int buf_appendi_lo(BUFFER *b, int i); + appends the two bytes representing i in little-endian byte order to buf. + + +int buf_appendl(BUFFER *buf, long l); + appends the four bytes representing l in big-endian byte order to buf. + + +int buf_appendl_lo(BUFFER *buf, long l); + appends the four bytes representing l in little-endian byte order to buf. + + +int buf_prepare(BUFFER *buf, int size); + sets buf to contain size bytes of arbitrary data. + + +int buf_get(BUFFER *buf, BUFFER *t, int n); + + This function sets buffer t to contain n bytes read from buf. + + Return values: + 0 on success, + -1 if buf does not contain n unread bytes. + + +int buf_getc(BUFFER *buf); + reads one byte from buf. Returns -1 if buf contains no unread data, + the byte otherwise. + + +int buf_geti(BUFFER *buf); + reads two bytes from buf. Returns -1 if buf buf does not contain two + unread bytes, the integer represented by the bytes in big-endian + byte order otherwise. + + +int buf_geti_lo(BUFFER *buf); + reads two bytes from buf. Returns -1 if buf buf does not contain two + unread bytes, the integer represented by the bytes in little-endian + byte order otherwise. + + +long buf_getl(BUFFER *buf); + reads four bytes from buf. Returns -1 if buf buf does not contain four + unread bytes, the integer represented by the bytes in big-endian + byte order otherwise. + + +long buf_getl_lo(BUFFER *buf); + reads four bytes from buf. Returns -1 if buf buf does not contain four + unread bytes, the integer represented by the bytes in little-endian + byte order otherwise. + + +void buf_ungetc(BUFFER *buf); + restores one character for reading. + + +int buf_appendb(BUFFER *buf, BUFFER *p); + appends p (with length information) to buf. + + +int buf_getb(BUFFER *buf, BUFFER *p); + gets length information, then p from buf. + + +int buf_getline(BUFFER *buf, BUFFER *line); + + This function reads one line of text from buf, and stores it (without + the trailing newline) in the buffer line. + + Return values: + 0 if a line of text has been read, + 1 if the line read is empty, + -1 if buf contains no unread data. + + +int buf_lookahead(BUFFER *buf, BUFFER *line); + + This function reads one line of text from buf, and stores it (without + the trailing newline) in the buffer line, without increasing the read + counter. + + Return values: + 0 if a line of text has been read, + 1 if the line read is empty, + -1 if buf contains no unread data. + + +int buf_chop(BUFFER *buf); + + buf is assumed to contain one line of text. A trailing newline and any + other lines of text buf may contain are removed. + + +int buf_isheader(BUFFER *buf); + + This function checks whether the first line of buf is a RFC 822 header line. + + Returns: + 0 if it is not a header line. + 1 if it is a header line. + +int buf_getheader(BUFFER *buf, BUFFER *field, BUFFER *content); + + This function reads a RFC 822 header line from buf. The field name of + the header line without the colon is stored in field, the line's + contents in content. + + Returns: + 0 on success, + 1 at end of header, + -1 if buf contains no unread data. + + +int buf_appendheader(BUFFER *buffer, BUFFER *field, BUFFER *content); + + This function appends the RFC 822 header consisting of field and content + to buffer. + + +int buf_rewind(BUFFER *buf); + + This function sets the read counter of buf to the start of the buffer + (equivalent to buf->ptr = 0). + + +Randomness +========== + +byte rnd_byte(void); + returns a random byte. + + +int rnd_number(int n); + returns a random number in 0 .. n-1. + + +int rnd_bytes(byte *b, int n); + stores n random bytes at b. + + +Interface to the crypto library PRNG +==================================== + +int rnd_init(void); + + initializes the PRNG from the random seed file. Called from mix_init(). + Return values: + 0 on success, + -1 on error. + + +int rnd_final(void); + + writes the random seed file and ends the PRNG. Called from mix_exit(). + Return values: + 0 on success, + -1 on error. + + +int rnd_seed(void); + seeds the PRNG, using console input if necessary. + + +void rnd_update(byte *b, int n); + adds n bytes from b to the PRNG, unless b == NULL, and adds randomness + from the system environment. + + +extern int rnd_state; + An application may set rnd_state = RND_WILLSEED before executing + mix_init() to indicate that it will seed the PRNG later by making calls + to rnd_update() and then to rnd_initialized(). In that case, + rnd_seed() will not ask for user input. [This is what the DLL startup code + does internally.] + + +String comparison +================= + +These functions operate on null-terminated strings. They return truth +values. + + +int streq(const char *s1, const char *s2); + + Return values: + 1 if the strings s1 and s2 are equal, + 0 otherwise. + + +int strieq(const char *s1, const char *s2); + + Return values: + 1 if the strings s1 and s2 are equal except for case, + 0 otherwise. + + +int strleft(const char *s, const char *keyword); + + Return values: + 1 if keyword is the left part of s, + 0 otherwise. + + +int strileft(const char *s, const char *keyword); + + Return values: + 1 if keyword is the left part of s, except for case, + 0 otherwise. + + +int strfind(const char *s, const char *keyword); + + Return values: + 1 if keyword is contained in s, + 0 otherwise. + + +int strifind(const char *s, const char *keyword); + + Return values: + 1 if keyword is contained in s, except for case, + 0 otherwise. + + +RFC 822 Addresses +================= + +void rfc822_addr(BUFFER *destination, BUFFER *list); + stores a list of RFC 822 addresses from destination in list, separated + by newlines. + +void rfc822_name(BUFFER *line, BUFFER *name); + stores the name given in the RFC 822 address in line in name. + + +Files and Pipes +=============== + +int mixfile(char path[PATHMAX], const char *name); + stores the path to a given file in the Mixmaster directory in path[]. + + +FILE *mix_openfile(const char *name, const char *a); + opens a file in the Mixmaster directory. + + +LOCK *lockfile(char *filename); + creates and locks a lockfile associated with filename. + + +int unlockfile(LOCK *lock); + releases the lock and deletes the lockfile. + + +int lock(FILE *f); + sets a lock on a file. + + +int unlock(FILE *f); + releases a lock on a file. + + +FILE *openpipe(const char *prog); + opens a pipe. + + +int closepipe(FILE *p); + closes a pipe. + + +int sendmail(BUFFER *message, BUFFER *address, const char *from); + + This function sends a mail message. The From: line and the destination + address may be contained in the message; in that case address and from + must be NULL. address is checked against the destination block list. + +int sendmail_loop(BUFFER *message, BUFFER *address, const char *from); + + Identical to sendmail() but adds an X-Loop: header line. + + +Printable Encoding +================== + +int encode(BUFFER *buf, int linelen); + + buf is encoded in base 64 encoding [RFC 1421]. If linelen > 0, the + resulting text is broken into lines of linelen characters. + + Return value: 0. + + +int decode(BUFFER *in, BUFFER *out); + + This function reads the unread data from in, as long as it is valid + base 64 encoded text, and stores the decoded data in out. + + Return values: + 0 if the in could be decoded to the end, + -1 otherwise. + + +int hdr_encode(BUFFER *in, int n); + + Encodes a header line according to the MIME standard. The header is + broken into lines of at most n characters. + + +int mail_encode(BUFFER *in, int encoding); + + Encodes the mail headers of a message, and encodes the body according + to encoding MIME_7BIT or MIME_8BIT. + + +void id_encode(byte id[16], byte *s); + stores the hexadecimal representation of id in s. + + +void id_decode(byte *s, byte id[16]); + sets id to the value of the hexadecimal string s. + + +Compression +=========== + +int buf_zip(BUFFER *buf, BUFFER *f, int b); + + compresses buffer f using GZIP with b bits (or a default value, if + b == 0), and appends the result to buf. + + Return values: + 0 on success, + -1 on error. + + +int buf_unzip(BUFFER *buf, int type); + + uncompresses a GZIP [RFC 1952] compressed buffer. If type == 1, uncompress + a ZLIB [RFC 1950] compressed buffer. + + Return values: + 0 on success, + -1 on error. + + +**************************************************************************/ + +#ifndef _MIXLIB_H +#define _MIXLIB_H + +#include <stdio.h> +#include <time.h> +#ifdef WIN32 +#include <windows.h> +#endif /* WIN32 */ + +typedef unsigned char byte; + +typedef struct { + byte *data; + long length; + long ptr; + long size; + byte sensitive; +} BUFFER; + +int mix_init(char *); +void mix_exit(void); +void rnd_update(byte *b, int n); +void rnd_initialized(void); +#ifdef WIN32 +int rnd_mouse(UINT i, WPARAM w, LPARAM l); +#endif /* WIN32 */ + +BUFFER *buf_new(void); +int buf_free(BUFFER *buf); +int buf_read(BUFFER *message, FILE *infile); +int buf_write(BUFFER *message, FILE *outfile); +int buf_write_sync(BUFFER *message, FILE *outfile); + +#define MSG_MAIL 1 +#define MSG_POST 2 +#define MSG_NULL 0 + +extern char MIXDIR[]; + +int mix_encrypt(int type, BUFFER *message, char *chain, int numcopies, + BUFFER *feedback); +int mix_decrypt(BUFFER *message); +int mix_send(void); + +#define FORCE_POOL 1 +#define FORCE_POP3 2 +#define FORCE_DAILY 4 +#define FORCE_MAILIN 8 +#define FORCE_STATS 16 +void mix_check_timeskew(void); +int mix_regular(int force); +int mix_daemon(void); +int process_mailin(void); + +#ifdef USE_PGP + +#define NYM_CREATE 0 +#define NYM_MODIFY 1 +#define NYM_DELETE 2 + +int nym_config(int mode, char *nym, char *nymserver, BUFFER *pseudonym, + char *sendchain, int sendnumcopies, BUFFER *chains, + BUFFER *options); +int nym_encrypt(BUFFER *msg, char *nym, int type); +int nym_decrypt(BUFFER *msg, char *nym, BUFFER *log); + +#define PGP_SIGN 1 +#define PGP_ENCRYPT 2 +#define PGP_CONVENTIONAL 4 +#define PGP_REMAIL 8 +#define PGP_TEXT 16 +#define PGP_NOARMOR 32 +#define PGP_DETACHEDSIG 64 +#define PGP_NCONVENTIONAL 128 +#define PGP_CONV3DES 256 +#define PGP_CONVCAST 512 + +/* error codes */ +#define PGP_OK 0 /* valid message, not signed */ +#define PGP_SIGOK 1 /* valid signature */ +#define PGP_NOMSG 2 /* is not an OpenPGP message */ +#define PGP_NODATA 3 /* OpenPGP packet does not contain user data */ +#define PGP_SIGNKEY 4 /* can't verify signature */ +#define PGP_ERR -1 /* can't read message, no matching key found */ +#define PGP_PASS -2 /* bad passphrase */ +#define PGP_SIGBAD -3 /* bad signature */ + + +/* algorithms */ +#define PGP_ANY 0 +#define PGP_ES_RSA 1 +#define PGP_E_ELG 16 +#define PGP_S_DSA 17 + +int pgp_encrypt(int mode, BUFFER *message, BUFFER *encr, BUFFER *sigid, + BUFFER *pass, char *pubring, char *secring); +int pgp_decrypt(BUFFER *message, BUFFER *pass, BUFFER *sig, char *pubring, + char *secring); +int pgp_keygen(int algo, int bits, BUFFER *userid, BUFFER *pass, + char *pubring, char *secring, int remail); +#endif /* USE_PGP */ + + +/* parsedate */ +time_t parsedate(char *p); + + + +#ifdef WIN32 + +#define sleep(x) Sleep((x)*1000) +#define strcasecmp stricmp + +#endif /* WIN32 */ + +#endif /* not _MIXLIB_H */ diff --git a/Src/mix3.h b/Src/mix3.h @@ -0,0 +1,443 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Function prototypes + $Id: mix3.h 934 2006-06-24 13:40:39Z rabbi $ */ + + +#ifndef _MIX3_H +#define _MIX3_H +#define COPYRIGHT "Copyright Anonymizer Inc. et al." + +#include "config.h" +#include "mix.h" + +#ifdef WIN32 +#ifndef USE_SOCK +#define _WINSOCKAPI_ /* don't include winsock */ +#endif /* not USE_SOCK */ +#include <windows.h> +#ifdef _MSC +#define snprintf _snprintf +#endif /* _MSC */ +#define DIRSEP '\\' +#define DIRSEPSTR "\\" +#else /* end of WIN32 */ +#define DIRSEP '/' +#define DIRSEPSTR "/" +#endif /* else if not WIN32 */ + +#define NOT_IMPLEMENTED {printf("Function not implemented.\n");return -1;} +#define SECONDSPERDAY 86400 + +#include <time.h> + +/* Dynamically allocated buffers */ + +int buf_reset(BUFFER *buffer); +int buf_clear(BUFFER *buffer); +int buf_append(BUFFER *buffer, byte *mess, int len); +int buf_cat(BUFFER *to, BUFFER *from); +int buf_set(BUFFER *to, BUFFER *from); +int buf_rest(BUFFER *to, BUFFER *from); +int buf_appendrnd(BUFFER *to, int n); +int buf_appendzero(BUFFER *to, int n); +int buf_setc(BUFFER *buf, byte c); +int buf_appendc(BUFFER *to, byte b); +int buf_setrnd(BUFFER *b, int n); +int buf_setf(BUFFER *buffer, char *fmt, ...); +int buf_appendf(BUFFER *buffer, char *fmt, ...); +int buf_sets(BUFFER *buf, char *s); +int buf_appends(BUFFER *buffer, char *s); +int buf_nl(BUFFER *buffer); +int buf_pad(BUFFER *buffer, int size); +int buf_prepare(BUFFER *buffer, int size); +int buf_rewind(BUFFER *buffer); +int buf_getc(BUFFER *buffer); +void buf_ungetc(BUFFER *buffer); +int buf_get(BUFFER *buffer, BUFFER *to, int n); +int buf_getline(BUFFER *buffer, BUFFER *line); +int buf_chop(BUFFER *b); +void buf_move(BUFFER *dest, BUFFER *src); +byte *buf_data(BUFFER *buffer); +int buf_isheader(BUFFER *buffer); +int buf_getheader(BUFFER *buffer, BUFFER *field, BUFFER *content); +int buf_appendheader(BUFFER *buffer, BUFFER *field, BUFFER *contents); +int buf_lookahead(BUFFER *buffer, BUFFER *line); +int buf_eq(BUFFER *b1, BUFFER *b2); +int buf_ieq(BUFFER *b1, BUFFER *b2); +void buf_cut_out(BUFFER *buffer, BUFFER *cut_out, BUFFER *rest, + int from, int len); + +int buf_appendl(BUFFER *b, long l); +int buf_appendl_lo(BUFFER *b, long l); +long buf_getl(BUFFER *b); +long buf_getl_lo(BUFFER *b); +int buf_appendi(BUFFER *b, int i); +int buf_appendi_lo(BUFFER *b, int i); +int buf_geti(BUFFER *b); +int buf_geti_lo(BUFFER *b); + +/* String comparison */ +int strieq(const char *s1, const char *s2); +int strileft(const char *string, const char *keyword); +int striright(const char *string, const char *keyword); +int strifind(const char *string, const char *keyword); + +int streq(const char *s1, const char *s2); +int strfind(const char *string, const char *keyword); +int strleft(const char *string, const char *keyword); + +void strcatn(char *dest, const char *src, int n); + +int bufleft(BUFFER *b, char *k); +int buffind(BUFFER *b, char *k); +int bufeq(BUFFER *b, char *k); + +int bufileft(BUFFER *b, char *k); +int bufifind(BUFFER *b, char *k); +int bufiright(BUFFER *b, char *k); +int bufieq(BUFFER *b, char *k); + +/* Utility functions */ +void whoami(char *addr, char *defaultname); +int sendinfofile(char *name, char *log, BUFFER *address, BUFFER *subject); +int stats(BUFFER *out); +int conf(BUFFER *out); +void conf_premail(BUFFER *out); + +void rfc822_addr(BUFFER *line, BUFFER *list); +void rfc822_name(BUFFER *line, BUFFER *name); +void sendmail_begin(void); /* begin mail sending session */ +void sendmail_end(void); /* end mail sending session */ +int sendmail_loop(BUFFER *message, char *from, BUFFER *address); +int sendmail(BUFFER *message, char *from, BUFFER *address); +int mixfile(char *path, const char *name); +int file_to_out(const char *name); +FILE *mix_openfile(const char *name, const char *a); +FILE *openpipe(const char *prog); +int closepipe(FILE *fp); +int maildirWrite(char *maildir, BUFFER *message, int create); +int write_pidfile(char *pidfile); +int clear_pidfile(char *pidfile); +time_t parse_yearmonthday(char* str); + +int url_download(char* url, char* dest); +int download_stats(char *sourcename); + +typedef struct { + char *name; + FILE *f; +} LOCK; + +int lock(FILE *f); +int unlock(FILE *f); +LOCK *lockfile(char *filename); +int unlockfile(LOCK *lock); + +int filtermsg(BUFFER *msg); +BUFFER *readdestblk( ); +int doblock(BUFFER *line, BUFFER *filter, int logandreset); +int doallow(BUFFER *line, BUFFER *filter); +int allowmessage(BUFFER *in); + +void errlog(int type, char *format,...); +void clienterr(BUFFER *msgbuf, char *err); +void logmail(char *mailbox, BUFFER *message); + +void mix_status(char *fmt,...); +void mix_genericerror(void); + +#define ERRORMSG 1 +#define WARNING 2 +#define NOTICE 3 +#define LOG 4 +#define DEBUGINFO 5 + +int decode(BUFFER *in, BUFFER *out); +int encode(BUFFER *b, int linelen); +void id_encode(byte id[], byte *s); +void id_decode(byte *s, byte id[]); + +int decode_header(BUFFER *content); +int boundary(BUFFER *line, BUFFER *mboundary); +void get_parameter(BUFFER *content, char *attribute, BUFFER *value); +int get_type(BUFFER *content, BUFFER *type, BUFFER *subtype); +int mail_encode(BUFFER *in, int encoding); +int hdr_encode(BUFFER *in, int n); +int attachfile(BUFFER *message, BUFFER *filename); +int pgpmime_sign(BUFFER *message, BUFFER *uid, BUFFER *pass, char *secring); +int mime_attach(BUFFER *message, BUFFER *attachment, BUFFER *type); +void mimedecode(BUFFER *msg); +int qp_decode_message(BUFFER *msg); + +#define MIME_8BIT 1 /* transport is 8bit */ +#define MIME_7BIT 2 /* transport is 7bit */ + +/* randomness */ +int rnd_bytes(byte *b, int n); +byte rnd_byte(void); +int rnd_number(int n); +int rnd_add(byte *b, int l); +int rnd_seed(void); +void rnd_time(void); + +int rnd_init(void); +int rnd_final(void); +void rnd_error(void); + +#define RND_QUERY 0 +#define RND_NOTSEEDED -1 +#define RND_SEEDED 1 +#define RND_WILLSEED 2 +extern int rnd_state; /* flag for PRNG status */ + +/* compression */ +int buf_compress(BUFFER *b); +int buf_zip(BUFFER *out, BUFFER *in, int bits); +int buf_uncompress(BUFFER *b); +int buf_unzip(BUFFER *b, int type); + +/* crypto functions */ +int digest_md5(BUFFER *b, BUFFER *md); +int isdigest_md5(BUFFER *b, BUFFER *md); +int digestmem_md5(byte *b, int n, BUFFER *md); +int digest_sha1(BUFFER *b, BUFFER *md); +int digest_rmd160(BUFFER *b, BUFFER *md); + +#define KEY_ID_LEN 32 +int keymgt(int force); +int key(BUFFER *b); +int adminkey(BUFFER *b); + +#define ENCRYPT 1 +#define DECRYPT 0 +int buf_crypt(BUFFER *b, BUFFER *key, BUFFER *iv, int enc); + +#ifdef USE_IDEA +int buf_ideacrypt(BUFFER *b, BUFFER *key, BUFFER *iv, int enc); +#endif /* USE_IDEA */ +int buf_bfcrypt(BUFFER *b, BUFFER *key, BUFFER *iv, int enc); +int buf_3descrypt(BUFFER *b, BUFFER *key, BUFFER *iv, int enc); +int buf_castcrypt(BUFFER *b, BUFFER *key, BUFFER *iv, int enc); +#ifdef USE_AES +int buf_aescrypt(BUFFER *b, BUFFER *key, BUFFER *iv, int enc); +#endif /* USE_AES */ + +int db_getseckey(byte keyid[], BUFFER *key); +int db_getpubkey(byte keyid[], BUFFER *key); +int pk_decrypt(BUFFER *encrypted, BUFFER *privkey); +int pk_encrypt(BUFFER *plaintext, BUFFER *privkey); +int check_seckey(BUFFER *buf, const byte id[]); +int check_pubkey(BUFFER *buf, const byte id[]); +int v2createkey(void); +int getv2seckey(byte keyid[], BUFFER *key); +int seckeytopub(BUFFER *pub, BUFFER *sec, byte keyid[]); + +/* configuration, general remailer functions */ +int mix_configline(char *line); +int mix_config(void); +int mix_initialized(void); +int mix_daily(void); + +/* message pool */ +#define INTERMEDIATE 0 +int pool_send(void); +int pool_read(BUFFER *pool); +int pool_add(BUFFER *msg, char *type); +FILE *pool_new(char *type, char *tmpname, char *path); +int mix_pool(BUFFER *msg, int type, long latent); +int pool_packetfile(char *fname, BUFFER *mid, int packetnum); +void pool_packetexp(void); +int idexp(void); +int pgpmaxexp(void); +void pop3get(void); + +typedef struct { /* added for binary id.log change */ + char id[16]; + long time; +} idlog_t; + +/* statistics */ +int stats_log(int); +int stats_out(int); + +/* OpenPGP */ +#define PGP_ARMOR_NORMAL 0 +#define PGP_ARMOR_REM 1 +#define PGP_ARMOR_KEY 2 +#define PGP_ARMOR_NYMKEY 3 +#define PGP_ARMOR_NYMSIG 4 +#define PGP_ARMOR_SECKEY 5 + +#define PGP_TYPE_UNDEFINED 0 +#define PGP_TYPE_PRIVATE 1 +#define PGP_TYPE_PUBLIC 2 + +int pgp_keymgt(int force); +int pgp_latestkeys(BUFFER* outtxt, int algo); +int pgp_armor(BUFFER *buf, int mode); +int pgp_dearmor(BUFFER *buf, BUFFER *out); +int pgp_pubkeycert(BUFFER *userid, char *keyring, BUFFER *pass, + BUFFER *out, int remail); +int pgp_signtxt(BUFFER *msg, BUFFER *uid, BUFFER *pass, + char *secring, int remail); +int pgp_isconventional(BUFFER *buf); +int pgp_mailenc(int mode, BUFFER *msg, char *sigid, + BUFFER *pass, char *pubring, char *secring); +int pgp_signhashalgo(BUFFER *algo, BUFFER *userid, char *secring, + BUFFER *pass); + +/* menu */ +int menu_initialized; +void menu_main(void); +void menu_folder(char command, char *name); +int menu_getuserpass(BUFFER *p, int mode); + +int user_pass(BUFFER *b); +int user_confirmpass(BUFFER *b); +void user_delpass(void); + +/* remailer */ +typedef struct { + char name[20]; + int version; + char addr[128]; + byte keyid[16]; + struct { + unsigned int mix:1; + unsigned int compress:1; + + unsigned int cpunk:1; + unsigned int pgp:1; + unsigned int pgponly:1; + unsigned int latent:1; + unsigned int hash:1; + unsigned int ek:1; + unsigned int esub:1; + + unsigned int nym:1; + unsigned int newnym:1; + + unsigned int post:1; + unsigned int middle:1; + + unsigned int star_ex:1; + } flags; + struct rinfo { + int reliability; + int latency; + char history[13]; + } info[2]; +} REMAILER; + +#define CHAINMAX 421 +#define MAXREM 100 +int prepare_type2list(BUFFER *out); +int mix2_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM]); +int t1_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM]); +int pgp_rlist(REMAILER remailer[], int n); +int pgp_rkeylist(REMAILER remailer[], int keyid[], int n); +void parse_badchains(int badchains[MAXREM][MAXREM], char *file, char *startindicator, REMAILER *remailer, int maxrem); +int chain_select(int hop[], char *chainstr, int maxrem, REMAILER *remailer, + int type, BUFFER *feedback); +int chain_rand(REMAILER *remailer, int badchains[MAXREM][MAXREM], int maxrem, + int thischain[], int chainlen, int t, int ignore_constraints_if_necessary); +int chain_randfinal(int type, REMAILER *remailer, int badchains[MAXREM][MAXREM], + int maxrem, int rtype, int chain[], int chainlen, int ignore_constraints_if_necessary); + +float chain_reliability(char *chain, int chaintype, + char *reliability_string); +int redirect_message(BUFFER *sendmsg, char *chain, int numcopies, BUFFER *chainlist); +int mix2_encrypt(int type, BUFFER *message, char *chainstr, int numcopies, + int ignore_constraints_if_necessary, BUFFER *feedback); +int t1_encrypt(int type, BUFFER *message, char *chainstr, int latency, + BUFFER *ek, BUFFER *feedback); + +int t1_getreply(BUFFER *msg, BUFFER *ek, int len); + +int t1_decrypt(BUFFER *in); +int t2_decrypt(BUFFER *in); + +int mix2_decrypt(BUFFER *m); +int v2body(BUFFER *body); +int v2body_setlen(BUFFER *body); +int v2partial(BUFFER *body, BUFFER *mid, int packet, int numpackets); +int v2_merge(BUFFER *mid); +int mix_armor(BUFFER *in); +int mix_dearmor(BUFFER *armored, BUFFER *bin); + +/* type 1 */ +#define HDRMARK "::" +#define EKMARK "**" +#define HASHMARK "##" +int isline(BUFFER *line, char *text); + +/* nym database */ + +#define NYM_WAITING 0 +#define NYM_OK 1 +#define NYM_DELETED 2 +#define NYM_ANY -1 + +int nymlist_read(BUFFER *n); +int nymlist_write(BUFFER *list); +int nymlist_get(BUFFER *list, char *nym, BUFFER *config, BUFFER *ek, + BUFFER *options, BUFFER *name, BUFFER *rblocks, int *status); +int nymlist_append(BUFFER *list, char *nym, BUFFER *config, BUFFER *options, + BUFFER *name, BUFFER *chains, BUFFER *eklist, int status); +int nymlist_del(BUFFER *list, char *nym); +int nymlist_getnym(char *nym, BUFFER *config, BUFFER *ek, BUFFER *opt, + BUFFER *name, BUFFER *rblocks); +int nymlist_getstatus(char *nym); + +/* Visual C lacks dirent */ +#ifdef _MSC +typedef HANDLE DIR; + +struct dirent { + char d_name[PATHMAX]; +}; + +DIR *opendir(const char *name); +struct dirent *readdir(DIR *dir); +int closedir(DIR *dir); +#endif /* _MSC */ + +/* sockets */ +#if defined(WIN32) && defined(USE_SOCK) +#include <winsock.h> +int sock_init(void); +void sock_exit(void); + +#else /* end of defined(WIN32) && defined(USE_SOCK) */ +typedef int SOCKET; + +#define INVALID_SOCKET -1 +SOCKET opensocket(char *hostname, int port); +int closesocket(SOCKET s); + +#endif /* else if not defined(WIN32) && defined(USE_SOCK) */ + +#ifdef WIN32 +int is_nt_service(void); +void set_nt_exit_event(); +#endif /* WIN32 */ + +/* check for memory leaks */ +#ifdef DEBUG +#define malloc mix3_malloc +#define free mix3_free +BUFFER *mix3_bufnew(char *, int, char*); +#if __GNUC__ >= 2 +# define buf_new() mix3_bufnew(__FILE__, __LINE__, __PRETTY_FUNCTION__) +#else /* end of __GNUC__ >= 2 */ +# define buf_new() mix3_bufnew(__FILE__, __LINE__, "file") +#endif /* else if not __GNUC__ >= 2 */ +#endif /* DEBUG */ + +#endif /* not _MIX3_H */ diff --git a/Src/mixlib.def b/Src/mixlib.def @@ -0,0 +1,121 @@ +LIBRARY MIXLIB + +DESCRIPTION 'Mixmaster MIXLIB.DLL - http://mixmaster.anonymizer.com' + +EXPORTS + mix_init @1 + mix_exit @2 + buf_new @3 + buf_free @4 + buf_read @5 + buf_write @6 + mix_encrypt @7 + mix_decrypt @8 + mix_send @9 + mix_regular @10 +; nym_config @11 +; nym_encrypt @12 +; nym_decrypt @13 + t1_decrypt @14 + t2_decrypt @15 + mix_pool @16 + pgp_encrypt @17 + pgp_mailenc @18 + pgp_decrypt @19 + pgp_keygen @20 + buf_reset @21 + buf_clear @22 + buf_eq @23 + buf_append @24 + buf_appendc @25 + buf_appends @26 + buf_appendf @27 + buf_sets @28 + buf_nl @29 + buf_cat @30 + buf_rest @31 + buf_set @32 + buf_move @33 + buf_appendrnd @34 + buf_setrnd @35 + buf_appendzero @36 + buf_appendi @37 + buf_appendi_lo @38 + buf_appendl @39 + buf_appendl_lo @40 + buf_prepare @41 + buf_getc @42 + buf_geti @43 + buf_geti_lo @44 + buf_getl @45 + buf_getl_lo @46 + buf_ungetc @47 + buf_appendb @48 + buf_getb @49 + buf_getline @50 + buf_lookahead @51 + buf_chop @52 + buf_getheader @53 + buf_rewind @54 + rnd_init @55 + streq @56 + strieq @57 + strleft @58 + strileft @59 + strfind @60 + strifind @61 + rfc822_addr @62 + rfc822_name @63 + mixfile @64 + mix_daemon @65 + mix_openfile @66 + sendmail @67 + encode @68 + decode @69 + hdr_encode @70 + mail_encode @71 + id_encode @72 + id_decode @73 + errlog @74 + keymgt @75 + menu_folder @76 + user_pass @77 + pop3get @78 + mix_configline @79 + rnd_time @80 + rnd_add @81 + rnd_update @82 + pool_read @83 + bufieq @84 + buf_appendheader @85 + attachfile @86 + rnd_initialized @87 + rnd_mouse @88 + user_delpass @89 + strcatn @90 + file_to_out @91 + is_nt_service @92 + set_nt_exit_event @93 + prepare_type2list @94 + NYMSECRING @95 + pgp_dearmor @96 + pgp_armor @97 + pgp_compress @98 + pgp_literal @99 + PGPSECRING @100 + PGPPUBRING @101 + VERBOSE @102 + pgp_signtxt @103 + pool_add @104 + getv2seckey @105 + pgpdb_getkey @106 + ENTEREDPASSPHRASE @107 + PASSPHRASE @108 + mix_config @109 + RATE @110 + SENDPOOLTIME @111 + CLIENTAUTOFLUSH @112 + redirect_message @113 + mix_check_timeskew @114 + MIXCONF @115 + menu_main @116 diff --git a/Src/mpgp.c b/Src/mpgp.c @@ -0,0 +1,264 @@ +/* mpgp -- (C) 2000 - 2006 Ulf Moeller and others. + + mpgp may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Test application for OpenPGP features + $Id: mpgp.c 934 2006-06-24 13:40:39Z rabbi $ */ + +#define MPGPVERSION "0.3.0" + +#include "mix3.h" +#include "pgp.h" +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <fcntl.h> +#ifdef POSIX +#include <unistd.h> +#include <termios.h> +#endif /* POSIX */ + +int pass(BUFFER *b) +{ + char p[LINELEN]; + int fd; + int n; + +#ifdef HAVE_TERMIOS + struct termios attr; +#endif /* HAVE_TERMIOS */ + + fprintf(stderr, "enter passphrase: "); + fflush(stderr); +#ifdef HAVE_TERMIOS + fd = open("/dev/tty", O_RDONLY); + if (tcgetattr(fd, &attr) != 0) + return (-1); + attr.c_lflag &= ~ECHO; + attr.c_lflag |= ICANON; + if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) + return (-1); + n = read(fd, p, LINELEN); + + attr.c_lflag |= ECHO; + if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) + return (-1); + close(fd); + p[n - 1] = 0; + +#else /* end of HAVE_TERMIOS */ + fgets(p, LINELEN, stdin); + if (p[strlen(p)-1]=='\n') + p[strlen(p)-1] = 0; +#endif /* else if not HAVE_TERMIOS */ + + fprintf(stderr, "\n"); + buf_appends(b, p); + return (0); +} + +void usage(char *n) +{ + fprintf(stderr, "Usage: %s -e [-b] user@domain\n", n); + fprintf(stderr, " %s -s [-b] [yourname@domain]\n", n); + fprintf(stderr, " %s -c [-b]\n", n); + fprintf(stderr, " %s -C [-b]\n", n); + fprintf(stderr, " %s -d [passphrase]\n", n); + fprintf(stderr, " %s -g[r] yourname@domain [bits]\n", n); + fprintf(stderr, " %s -a[+-] [-b]\n", n); + fprintf(stderr, " %s -V\n\n", n); + fprintf(stderr, "PGP public key ring: %s\n", PGPPUBRING); + fprintf(stderr, "PGP secret key ring: %s\n", PGPSECRING); +} + +int decrypt(BUFFER *u, BUFFER *option, char *n) +{ + BUFFER *v; + BUFFER *sig; + int err = 0; + + v = buf_new(); + sig = buf_new(); + + buf_set(v, u); + err = pgp_decrypt(v, NULL, sig, PGPPUBRING, PGPSECRING); + if (err >= 0 || err == PGP_SIGBAD) + buf_move(u, v); + + if (err == PGP_ERR) { + pass(option); + err = pgp_decrypt(u, option, sig, PGPPUBRING, PGPSECRING); + } + switch (err) { + case PGP_NOMSG: + fprintf(stderr, "%s: Not a PGP message.\n", n); + break; + case PGP_ERR: + fprintf(stderr, "%s: Can't read message.\n", n); + break; + case PGP_SIGOK: + fprintf(stderr, "%s: Valid signature: %s\n", n, sig->data); + err = 0; + break; + case PGP_SIGNKEY: + fprintf(stderr, "%s: Unknown signature key %s, cannot verify.\n", n, sig->data); + err = 1; + break; + case PGP_SIGBAD: + fprintf(stderr, "%s: Bad signature.\n", n); + err = 1; + break; + } + + buf_free(v); + buf_free(sig); + + return (err); +} + +int main(int argc, char *argv[]) +{ + BUFFER *u, *option, *pp; + char *filename = NULL; + char *cmd = NULL; + int text = 1; + int err = 99; + int bits = 0; + + mix_init(NULL); + VERBOSE = 3; + + u = buf_new(); + option = buf_new(); + pp = buf_new(); + + if (argc > 1 && argv[1][0] == '-') + cmd = argv[1]; + + if (argc == 1 || (cmd > 0 && (cmd[1] == 'e' || cmd[1] == 'c' || + cmd[1] == 'd' || cmd[1] == 'a' || + cmd[1] == 's' || cmd[1] == 'C'))) { + if ((argc > 2 && (cmd == NULL || cmd[1] == 'a')) || argc > 3) { + FILE *f; + + f = fopen(argv[argc - 1], "rb"); + if (f == NULL) { + fprintf(stderr, "%s: Can't open %s\n", argv[0], argv[argc - 1]); + err = -1; + } else { + buf_read(u, f); + fclose(f); + filename = argv[argc - 1]; + argc--; + } + } else + buf_read(u, stdin); + } + if (argc == 1) + err = decrypt(u, option, argv[0]); + + if (argc > 2 && argv[2][0] == '-' && argv[2][1] == 'b') { + text = 0; + if (argc > 3) + buf_appends(option, argv[3]); + } else if (argc > 2) + buf_appends(option, argv[2]); + + if (cmd) + switch (cmd[1]) { + case 's': + err = pgp_encrypt(PGP_SIGN | (text ? PGP_TEXT : 0), u, NULL, option, + NULL, PGPPUBRING, PGPSECRING); + if (err != 0) { + pass(pp); + err = pgp_encrypt(PGP_SIGN | (text ? PGP_TEXT : 0), u, NULL, option, + pp, PGPPUBRING, PGPSECRING); + } + if (err != 0) + fprintf(stderr, "Error.\n"); + break; + case 'e': + if (option->length) { + err = pgp_encrypt(PGP_ENCRYPT | (text ? PGP_TEXT : 0), u, option, NULL, + NULL, PGPPUBRING, PGPSECRING); + if (err < 0) + fprintf(stderr, "%s: can't encrypt message for %s\n", + argv[0], argv[2]); + } + break; + case 'c': + pass(option); + err = pgp_encrypt(PGP_CONVENTIONAL | (text ? PGP_TEXT : 0), u, option, + NULL, NULL, PGPPUBRING, PGPSECRING); + if (err < 0) + fprintf(stderr, "%s: can't encrypt message\n", argv[0]); + break; + case 'C': + pass(option); + err = pgp_encrypt(PGP_NCONVENTIONAL | (text ? PGP_TEXT : 0), u, option, + NULL, NULL, PGPPUBRING, PGPSECRING); + if (err < 0) + fprintf(stderr, "%s: can't encrypt message\n", argv[0]); + break; + case 'g': + if (argc < 3) { + err = 99; + goto end; + } + pass(pp); + if (argc == 4) + sscanf(argv[3], "%d", &bits); + err = pgp_keygen(cmd[2] == 'r' ? PGP_ES_RSA : PGP_E_ELG, + bits, option, pp, PGPPUBRING, PGPSECRING, 0); + break; + case 'a': + switch (cmd[2]) { + case '-': + err = pgp_dearmor(u, u); + if (err == -1) + fprintf(stderr, "Not a PGP-armored message\n"); + goto end; + case '+': + break; + default: + pgp_literal(u, filename, text); + pgp_compress(u); + break; + } + err = pgp_armor(u, PGP_ARMOR_NORMAL); + break; + case 'd': + err = decrypt(u, option, argv[0]); + break; + case 'h': + usage(argv[0]); + err = 0; + break; + case 'V': + fprintf(stderr, "mpgp version %s\n", MPGPVERSION); + fprintf(stderr, "(C) 2000 - 2004 Ulf Moeller and others.\n"); + fprintf(stderr, "See the file COPYRIGHT for details.\n"); + err = 0; + break; + } +end: + if (err == 99) + usage(argv[0]); + + if (err >= 0) + buf_write(u, stdout); + + buf_free(option); + buf_free(pp); + buf_free(u); + + mix_exit(); + return (err == -1 ? 1 : err); +} diff --git a/Src/nym.c b/Src/nym.c @@ -0,0 +1,669 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Create nym server messages + $Id: nym.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#ifdef NYMSUPPORT + +#include "mix3.h" +#include "pgp.h" +#include <string.h> +#include <time.h> +#include <assert.h> + +int nym_config(int mode, char *nym, char *nymserver, BUFFER *pseudonym, + char *sendchain, int sendnumcopies, BUFFER *chains, + BUFFER *options) +{ +#ifndef USE_PGP + return (-1); +#else /* end of not USE_PGP */ + REMAILER remailer[MAXREM]; + int badchains[MAXREM][MAXREM]; + KEYRING *r; + int maxrem; + int chain[20]; + char rchain[CHAINMAX]; + BUFFER *userid, *msg, *req, *k, *line, *ek, *eklist, *key, *pubkey, *out, + *oldchains; + int latency; + int err = -1; + int status; + int desttype = MSG_MAIL; + int rblock = 0; + BUFFER *nymlist, *userpass, *config; + LOCK *nymlock; + + userid = buf_new(); + msg = buf_new(); + req = buf_new(); + k = buf_new(); + line = buf_new(); + ek = buf_new(); + eklist = buf_new(); + key = buf_new(); + pubkey = buf_new(); + out = buf_new(); + config = buf_new(); + nymlist = buf_new(); + userpass = buf_new(); + oldchains = buf_new(); + + for (;;) { + user_pass(userpass); + if (user_confirmpass(userpass)) + break; + user_delpass(); + } + + if (nymserver) { + maxrem = t1_rlist(remailer, badchains); + if (maxrem < 1) + return (-1); + if (chain_select(chain, nymserver, maxrem, remailer, 2, NULL) != 1) + return (-1); + if (chain[0] == 0) + chain[0] = chain_randfinal(MSG_MAIL, remailer, badchains, maxrem, 2, NULL, -1); + if (chain[0] == -1) + return (-1); + assert(strchr(nym, '@') == NULL && strchr(remailer[chain[0]].addr, '@')); + strcatn(nym, strchr(remailer[chain[0]].addr, '@'), LINELEN); + buf_appends(config, remailer[chain[0]].addr); + } else + assert(strchr(nym, '@') != NULL); + + status = nymlist_getnym(nym, config->length ? NULL : config, eklist, NULL, + NULL, oldchains); + if (mode == NYM_CREATE && status == NYM_OK) + mode = NYM_MODIFY; + + buf_appendc(userid, '<'); + buf_appends(userid, nym); + buf_appendc(userid, '>'); + + buf_sets(req, "Config:\nFrom: "); + buf_append(req, nym, strchr(nym, '@') - nym); + buf_appends(req, "\nNym-Commands:"); + if (mode == NYM_CREATE) + buf_appends(req, " create?"); + if (mode == NYM_DELETE) + buf_appends(req, " delete"); + else { + if (options && options->length > 0) { + if (!bufleft(options, " ")) + buf_appendc(req, ' '); + buf_cat(req, options); + } + if (pseudonym && pseudonym->length > 0) { + buf_appends(req, " name=\""); + buf_cat(req, pseudonym); + buf_appendc(req, '\"'); + } + } + buf_nl(req); + if (mode == NYM_CREATE) { + buf_appends(req, "Public-Key:\n"); + + getkey: + r = pgpdb_open(NYMSECRING, userpass, 0, PGP_TYPE_PRIVATE); + if (r == NULL) { + err = -3; + goto end; + } + if (r->filetype == -1) + r->filetype = 0; + + while (pgpdb_getnext(r, key, NULL, userid) != -1) + if (pgp_makepubkey(key, NULL, pubkey, userpass, 0) == 0) + err = 0; + pgpdb_close(r); + if (err != 0) { + if (err == -2) + goto end; + err = -2; + if (pseudonym && pseudonym->length) { + buf_set(userid, pseudonym); + buf_appendc(userid, ' '); + } else + buf_clear(userid); + buf_appendf(userid, "<%s>", nym); + pgp_keygen(PGP_ES_RSA, 0, userid, userpass, NULL, NYMSECRING, 2); + goto getkey; + } + pgp_armor(pubkey, PGP_ARMOR_NYMKEY); + buf_cat(req, pubkey); + } + if (mode != NYM_DELETE) { + if (nymlist_read(nymlist) == -1) { + user_delpass(); + err = -1; + goto end; + } + if (chains) + for (;;) { + err = buf_getheader(chains, k, line); + if (err == -1 && rblock == 0) + break; + if (err != 0 && rblock == 1) { + buf_setrnd(ek, 16); + if (t1_encrypt(desttype, msg, rchain, latency, ek, NULL) != 0) { + err = -2; + goto end; + } + encode(ek, 0); + buf_cat(eklist, ek); + buf_nl(eklist); + buf_appends(req, "Reply-Block:\n"); + buf_cat(req, msg); + buf_clear(msg); + rblock = 0; + continue; + } + if (bufieq(k, "Chain")) + strncpy(rchain, line->data, sizeof(rchain)); + else if (bufieq(k, "Latency")) + sscanf(line->data, "%d", &latency); + else if (bufieq(k, "Null")) + desttype = MSG_NULL, rblock = 1; + else { + buf_appendheader(msg, k, line); + if (bufieq(k, "To")) + desttype = MSG_MAIL, rblock = 1; + if (bufieq(k, "Newsgroups")) + desttype = MSG_POST, rblock = 1; + } + } + } + nymlock = lockfile(NYMDB); + if (nymlist_read(nymlist) == 0) { + nymlist_del(nymlist, nym); + nymlist_append(nymlist, nym, config, options, pseudonym, + chains ? chains : oldchains, eklist, + mode == NYM_DELETE ? NYM_DELETED : + (status == -1 ? NYM_WAITING : status)); + nymlist_write(nymlist); + } else + err = -1; + unlockfile(nymlock); + +#ifdef DEBUG + buf_write(req, stderr); +#endif /* DEBUG */ + buf_clear(line); + buf_appendc(line, '<'); + buf_cat(line, config); + buf_appendc(line, '>'); + + err = pgp_encrypt(PGP_ENCRYPT | PGP_SIGN | PGP_TEXT | PGP_REMAIL, + req, line, userid, userpass, NULL, NYMSECRING); + if (err != 0) + goto end; +#ifdef DEBUG + buf_write(req, stderr); +#endif /* DEBUG */ + buf_sets(out, "To: "); + buf_cat(out, config); + buf_nl(out); + buf_nl(out); + buf_cat(out, req); + + err = mix_encrypt(desttype, out, sendchain, sendnumcopies, line); + if (err) + mix_status("%s\n", line->data); + +end: + if (strchr(nym, '@')) *strchr(nym, '@') = '\0'; + buf_free(userid); + buf_free(msg); + buf_free(req); + buf_free(k); + buf_free(line); + buf_free(ek); + buf_free(eklist); + buf_free(key); + buf_free(pubkey); + buf_free(out); + buf_free(nymlist); + buf_free(userpass); + buf_free(oldchains); + buf_free(config); + return (err); +#endif /* else if USE_PGP */ +} + +int nym_encrypt(BUFFER *msg, char *nym, int type) +{ +#ifndef USE_PGP + return (-1); +#else /* end of not USE_PGP */ + BUFFER *out, *userpass, *sig, *config; + int err = -1; + + out = buf_new(); + userpass = buf_new(); + sig = buf_new(); + config = buf_new(); + + if (nymlist_getnym(nym, config, NULL, NULL, NULL, NULL) == NYM_OK) { + buf_appends(out, "From: "); + buf_append(out, nym, strchr(nym, '@') - nym); + buf_nl(out); + if (type == MSG_POST) { + buf_appends(out, "To: "); + buf_appends(out, MAILtoNEWS); + buf_nl(out); + } + buf_cat(out, msg); + mail_encode(out, 0); + buf_appendc(sig, '<'); + buf_appends(sig, nym); + buf_appendc(sig, '>'); +#ifdef DEBUG + buf_write(out, stderr); +#endif /* DEBUG */ + user_pass(userpass); + err = pgp_encrypt(PGP_ENCRYPT | PGP_SIGN | PGP_TEXT | PGP_REMAIL, + out, config, sig, userpass, NULL, NYMSECRING); + if (err == 0) { + buf_clear(msg); + buf_appends(msg, "To: send"); + buf_appends(msg, strchr(nym, '@')); + buf_nl(msg); + buf_nl(msg); + buf_cat(msg, out); + } + } + buf_free(out); + buf_free(config); + buf_free(userpass); + buf_free(sig); + return (err); +#endif /* else if USE_PGP */ +} + +int nym_decrypt(BUFFER *msg, char *thisnym, BUFFER *log) +{ +#ifndef USE_PGP + return (-1); +#else /* end of not USE_PGP */ + BUFFER *pgpmsg, *out, *line; + BUFFER *nymlist, *userpass; + BUFFER *decr, *sig, *mid; + BUFFER *name, *rblocks, *eklist, *config; + int decrypted = 0; + int err = 1; + long ptr; + char nym[LINELEN]; + BUFFER *ek, *opt; + int status; + LOCK *nymlock; + time_t t; + struct tm *tc; + char timeline[LINELEN]; + + pgpmsg = buf_new(); + out = buf_new(); + line = buf_new(); + nymlist = buf_new(); + userpass = buf_new(); + config = buf_new(); + ek = buf_new(); + decr = buf_new(); + sig = buf_new(); + mid = buf_new(); + opt = buf_new(); + name = buf_new(); + rblocks = buf_new(); + eklist = buf_new(); + + if (thisnym) + thisnym[0] = '\0'; + while ((ptr = msg->ptr, err = buf_getline(msg, line)) != -1) { + if (bufleft(line, begin_pgpmsg)) { + err = -1; + msg->ptr = ptr; + pgp_dearmor(msg, pgpmsg); + if (pgp_isconventional(pgpmsg)) { + user_pass(userpass); + nymlock = lockfile(NYMDB); + if (nymlist_read(nymlist) == -1) + user_delpass(); + while (nymlist_get(nymlist, nym, config, eklist, opt, name, + rblocks, &status) >= 0) { + while (buf_getline(eklist, ek) == 0) { + decode(ek, ek); + if (t1_getreply(pgpmsg, ek, 20) == 0) { + buf_clear(out); + err = pgp_decrypt(pgpmsg, userpass, sig, NULL, + NYMSECRING); + buf_sets(out, "From nymserver "); + if (strchr(sig->data, '[') && strchr(sig->data, ']')) + buf_append(out, strchr(sig->data, '[') + 1, + strchr(sig->data, ']') - + strchr(sig->data, '[') - 1); + else { + t = time(NULL); + tc = localtime(&t); + strftime(timeline, LINELEN, "%a %b %d %H:%M:%S %Y", tc); + buf_appends(out, timeline); + } + buf_nl(out); + if (err == PGP_SIGOK && + bufifind(sig, config->data)) { + buf_appends(out, "Nym: "); + if (status == NYM_WAITING) + buf_appends(out, "confirm "); + buf_appends(out, nym); + buf_nl(out); + if (thisnym && status == NYM_OK) + strncpy(thisnym, nym, LINELEN); + } else + buf_appends(out, "Warning: Signature verification failed!\n"); + buf_cat(out, pgpmsg); + decrypted = 2; + if (log) { + digest_md5(out, mid); + encode(mid, 0); + if (buffind(log, mid->data)) { + decrypted = -1; + unlockfile(nymlock); + goto end; + } else { + buf_cat(log, mid); + buf_nl(log); + } + } + if (status == NYM_WAITING) { + nymlist_del(nymlist, nym); + nymlist_append(nymlist, nym, config, opt, + name, rblocks, eklist, NYM_OK); + } + break; + } + } + } + nymlist_write(nymlist); + unlockfile(nymlock); + } + if (decrypted == 0) { + user_pass(userpass); + err = pgp_decrypt(pgpmsg, userpass, sig, PGPPUBRING, PGPSECRING); + if (err == PGP_ERR) + err = pgp_decrypt(pgpmsg, userpass, sig, PGPPUBRING, + NYMSECRING); +#if 0 + if (err == PGP_PASS || err == PGP_ERR) + user_delpass(); +#endif /* 0 */ + if (err != PGP_ERR && err != PGP_PASS && err != PGP_NOMSG && + err != PGP_NODATA) { + buf_appends(out, info_beginpgp); + if (err == PGP_SIGOK) + buf_appendf(out, " (SIGNED)\n%s%b", info_pgpsig, sig); + buf_nl(out); + buf_cat(out, pgpmsg); + buf_appends(out, info_endpgp); + buf_nl(out); + decrypted = 1; + } + } + if (decrypted == 0) { + buf_cat(out, line); + buf_nl(out); + } + } else { + if (bufileft(line, info_beginpgp)) + buf_appendc(out, ' '); /* escape info line in text */ + buf_cat(out, line); + buf_nl(out); + } + } + + if (decrypted) + buf_move(msg, out); + else + buf_rewind(msg); + if (decrypted == 2) + nym_decrypt(msg, thisnym, NULL); +end: + buf_free(pgpmsg); + buf_free(out); + buf_free(line); + buf_free(decr); + buf_free(sig); + buf_free(mid); + buf_free(opt); + buf_free(name); + buf_free(config); + buf_free(rblocks); + buf_free(eklist); + buf_free(nymlist); + buf_free(userpass); + buf_free(ek); + return (decrypted); +#endif /* else if USE_PGP */ +} + +int nymlist_read(BUFFER *list) +{ +#ifdef USE_PGP + BUFFER *key; + +#endif /* USE_PGP */ + FILE *f; + int err = 0; + + buf_clear(list); + f = mix_openfile(NYMDB, "rb"); + if (f != NULL) { + buf_read(list, f); + fclose(f); +#ifdef USE_PGP + key = buf_new(); + user_pass(key); + if (key->length) + if (pgp_decrypt(list, key, NULL, NULL, NULL) < 0) { + buf_clear(list); + err = -1; + } + buf_free(key); +#endif /* USE_PGP */ + } + return (err); +} + +int nymlist_write(BUFFER *list) +{ +#ifdef USE_PGP + BUFFER *key; + +#endif /* USE_PGP */ + FILE *f; + + if (list->length == 0) + return (-1); + +#ifdef USE_PGP + key = buf_new(); + user_pass(key); + if (key->length) + pgp_encrypt(PGP_NCONVENTIONAL | PGP_NOARMOR, list, key, NULL, NULL, NULL, + NULL); + buf_free(key); +#endif /* USE_PGP */ + f = mix_openfile(NYMDB, "wb"); + if (f == NULL) + return (-1); + else { + buf_write(list, f); + fclose(f); + } + return (0); +} + +int nymlist_get(BUFFER *list, char *nym, BUFFER *config, BUFFER *ek, + BUFFER *opt, BUFFER *name, BUFFER *chains, int *status) +{ + BUFFER *line; + int err = -1; + + line = buf_new(); + if (ek) + buf_clear(ek); + if (opt) + buf_clear(opt); + if (name) + buf_clear(name); + if (chains) + buf_clear(chains); + if (config) + buf_clear(config); + + for (;;) { + if (buf_getline(list, line) == -1) + goto end; + if (bufleft(line, "nym=")) + break; + } + strncpy(nym, line->data + 4, LINELEN); + + for (;;) { + if (buf_getline(list, line) == -1) + break; + if (opt && bufleft(line, "opt=")) + line->ptr = 4, buf_rest(opt, line); + if (name && bufleft(line, "name=")) + line->ptr = 5, buf_rest(name, line); + if (config && bufleft(line, "config=")) + line->ptr = 7, buf_rest(config, line); + if (bufeq(line, "ek=")) { + while (buf_getline(list, line) == 0 && !bufeq(line, "end ek")) + if (ek) { + buf_cat(ek, line); + buf_nl(ek); + } + } + if (bufeq(line, "chains=")) { + while (buf_getline(list, line) == 0 && !bufeq(line, "end chains")) + if (chains) { + buf_cat(chains, line); + buf_nl(chains); + } + } + if (status && bufleft(line, "status=")) + *status = line->data[7] - '0'; + if (bufeq(line, "end")) { + err = 0; + break; + } + } +end: + buf_free(line); + return (err); +} + +int nymlist_append(BUFFER *list, char *nym, BUFFER *config, BUFFER *opt, + BUFFER *name, BUFFER *rblocks, BUFFER *eklist, int status) +{ + buf_appends(list, "nym="); + buf_appends(list, nym); + buf_nl(list); + buf_appends(list, "config="); + buf_cat(list, config); + buf_nl(list); + buf_appends(list, "status="); + buf_appendc(list, (byte) (status + '0')); + buf_nl(list); + if (name) { + buf_appends(list, "name="); + buf_cat(list, name); + buf_nl(list); + } + buf_appends(list, "opt="); + buf_cat(list, opt); + buf_nl(list); + buf_appends(list, "chains=\n"); + buf_cat(list, rblocks); + buf_appends(list, "end chains\n"); + buf_appends(list, "ek=\n"); + buf_cat(list, eklist); + buf_appends(list, "end ek\n"); + buf_appends(list, "end\n"); + return (0); +} + +int nymlist_del(BUFFER *list, char *nym) +{ + BUFFER *new; + char thisnym[LINELEN]; + BUFFER *config, *ek, *name, *rblocks, *opt; + int thisstatus; + + new = buf_new(); + config = buf_new(); + ek = buf_new(); + name = buf_new(); + rblocks = buf_new(); + opt = buf_new(); + + buf_rewind(list); + while (nymlist_get(list, thisnym, config, ek, opt, name, rblocks, + &thisstatus) >= 0) + if (!streq(nym, thisnym)) + nymlist_append(new, thisnym, config, opt, name, rblocks, ek, + thisstatus); + + buf_move(list, new); + buf_free(new); + buf_free(name); + buf_free(opt); + buf_free(rblocks); + buf_free(config); + buf_free(ek); + return (0); +} + +int nymlist_getnym(char *nym, BUFFER *config, BUFFER *ek, BUFFER *opt, + BUFFER *name, BUFFER *rblocks) + /* "nym@nymserver.domain" or "nym@" */ +{ + BUFFER *nymlist, *userpass; + char n[LINELEN]; + int err = -1; + int status; + + nymlist = buf_new(); + userpass = buf_new(); + + user_pass(userpass); + if (nymlist_read(nymlist) != -1) { + while (nymlist_get(nymlist, n, config, ek, opt, name, rblocks, + &status) >= 0) + if (streq(nym, n) || (nym[strlen(nym) - 1] == '@' && strleft(n, nym))) { + err = status; + strncpy(nym, n, LINELEN); + break; + } + } + buf_free(userpass); + buf_free(nymlist); + return (err); +} + +int nymlist_getstatus(char *nym) +{ + int status; + + if ((status = nymlist_getnym(nym, NULL, NULL, NULL, NULL, NULL)) == 0) + return (status); + else + return (-1); +} + +#endif /* NYMSUPPORT */ diff --git a/Src/parsedate.y b/Src/parsedate.y @@ -0,0 +1,879 @@ +%{ +/* $Id: parsedate.y 647 2003-10-25 23:34:13Z weasel $ +** +** Originally written by Steven M. Bellovin <smb@research.att.com> while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990. +** Further revised (removed obsolete constructs and cleaned up timezone +** names) in August, 1991, by Rich. Paul Eggert <eggert@twinsun.com> +** helped in September, 1992. +** +** This grammar has six shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ + +#include <stdio.h> +#include <string.h> + +// #include "config.h" +// #include "clibrary.h" +#include <ctype.h> + +#if defined(_HPUX_SOURCE) +# include <alloca.h> +#endif + +#ifdef TM_IN_SYS_TIME +# include <sys/time.h> +#else +# include <time.h> +#endif + +// #include "libinn.h" + +/* Used for iterating through arrays. ARRAY_SIZE returns the number of + elements in the array (useful for a < upper bound in a for loop) and + ARRAY_END returns a pointer to the element past the end (ISO C99 makes it + legal to refer to such a pointer as long as it's never dereferenced). */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)]) + +/* On some systems, the macros defined by <ctype.h> are only vaild on ASCII + characters (those characters that isascii() says are ASCII). This comes + into play when applying <ctype.h> macros to eight-bit data. autoconf + checks for this with as part of AC_HEADER_STDC, so if autoconf doesn't + think our headers are standard, check isascii() first. */ +#if STDC_HEADERS +# define CTYPE(isXXXXX, c) (isXXXXX((unsigned char)(c))) +#else +# define CTYPE(isXXXXX, c) \ + (isascii((unsigned char)(c)) && isXXXXX((unsigned char)(c))) +#endif + + +#define yylhs date_yylhs +#define yylen date_yylen +#define yydefred date_yydefred +#define yydgoto date_yydgoto +#define yysindex date_yysindex +#define yyrindex date_yyrindex +#define yygindex date_yygindex +#define yytable date_yytable +#define yycheck date_yycheck +#define yyparse date_parse +#define yylex date_lex +#define yyerror date_error +#define yymaxdepth date_yymaxdepth + + +static int date_lex(void); + + + /* See the LeapYears table in Convert. */ +#define EPOCH 1970 +#define END_OF_TIME 2038 + /* Constants for general time calculations. */ +#define DST_OFFSET 1 +#define SECSPERDAY (24L * 60L * 60L) + /* Readability for TABLE stuff. */ +#define HOUR(x) (x * 60) + +#define LPAREN '(' +#define RPAREN ')' +#define IS7BIT(x) ((unsigned int)(x) < 0200) + + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + const char * name; + int type; + time_t value; +} TABLE; + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of them by using a yacc +** union, but this is more efficient. (This routine predates the +** yacc %union construct.) +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static int yyHaveDate; +static int yyHaveRel; +static int yyHaveTime; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + + +/* extern struct tm *localtime(); */ + +static void date_error(const char *s); +%} + +%union { + time_t Number; + enum _MERIDIAN Meridian; +} + +%token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT tSNUMBER +%token tUNUMBER tZONE + +%type <Number> tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT +%type <Number> tSNUMBER tUNUMBER tZONE numzone zone +%type <Meridian> tMERIDIAN o_merid + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { + yyHaveTime++; +#if defined(lint) + /* I am compulsive about lint natterings... */ + if (yyHaveTime == -1) { + YYERROR; + } +#endif /* defined(lint) */ + } + | time zone { + yyHaveTime++; + yyTimezone = $2; + } + | date { + yyHaveDate++; + } + | rel { + yyHaveRel = 1; + } + ; + +time : tUNUMBER o_merid { + if ($1 < 100) { + yyHour = $1; + yyMinutes = 0; + } + else { + yyHour = $1 / 100; + yyMinutes = $1 % 100; + } + yySeconds = 0; + yyMeridian = $2; + } + | tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + yyMeridian = $4; + } + | tUNUMBER ':' tUNUMBER numzone { + yyHour = $1; + yyMinutes = $3; + yyTimezone = $4; + yyMeridian = MER24; + yyDSTmode = DSToff; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = $6; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyTimezone = $6; + yyMeridian = MER24; + yyDSTmode = DSToff; + } + ; + +zone : tZONE { + $$ = $1; + yyDSTmode = DSToff; + } + | tDAYZONE { + $$ = $1; + yyDSTmode = DSTon; + } + | tZONE numzone { + /* Only allow "GMT+300" and "GMT-0800" */ + if ($1 != 0) { + YYABORT; + } + $$ = $2; + yyDSTmode = DSToff; + } + | numzone { + $$ = $1; + yyDSTmode = DSToff; + } + ; + +numzone : tSNUMBER { + int i; + + /* Unix and GMT and numeric timezones -- a little confusing. */ + if ($1 < 0) { + /* Don't work with negative modulus. */ + $1 = -$1; + if ($1 > 9999 || (i = $1 % 100) >= 60) { + YYABORT; + } + $$ = ($1 / 100) * 60 + i; + } + else { + if ($1 > 9999 || (i = $1 % 100) >= 60) { + YYABORT; + } + $$ = -(($1 / 100) * 60 + i); + } + } + ; + +date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + if ($1 > 100) { + /* assume YYYY/MM/DD format, so need not to add 1900 */ + if ($1 > 999) { + yyYear = $1; + } else { + yyYear = 1900 + $1; + } + yyMonth = $3; + yyDay = $5; + } + else { + /* assume MM/DD/YY* format */ + yyMonth = $1; + yyDay = $3; + if ($5 > 999) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = $5; + } else if ($5 < 100) { + /* assume year is YY format, so need to add 1900 */ + yyYear = $5 + (yyYear / 100 + (yyYear % 100 - $5) / 50) * 100; + } else { + yyYear = 1900 + $5; + } + } + } + | tMONTH tUNUMBER { + yyMonth = $1; + yyDay = $2; + } + | tMONTH tUNUMBER ',' tUNUMBER { + yyMonth = $1; + yyDay = $2; + if ($4 > 999) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = $4; + } else if ($4 < 100) { + /* assume year is YY format, so need to add 1900 */ + yyYear = $4 + (yyYear / 100 + (yyYear % 100 - $4) / 50) * 100; + } else { + yyYear = 1900 + $4; + } + } + | tUNUMBER tMONTH { + yyDay = $1; + yyMonth = $2; + } + | tUNUMBER tMONTH tUNUMBER { + yyDay = $1; + yyMonth = $2; + if ($3 > 999) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = $3; + } else if ($3 < 100) { + /* assume year is YY format, so need to add 1900 */ + yyYear = $3 + (yyYear / 100 + (yyYear % 100 - $3) / 50) * 100; + } else { + yyYear = 1900 + $3; + } + } + | tDAY ',' tUNUMBER tMONTH tUNUMBER { + yyDay = $3; + yyMonth = $4; + if ($5 > 999) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = $5; + } else if ($5 < 100) { + /* assume year is YY format, so need to add 1900 */ + yyYear = $5 + (yyYear / 100 + (yyYear % 100 - $5) / 50) * 100; + } else { + yyYear = 1900 + $5; + } + } + ; + +rel : tSNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tUNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tSNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tUNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + ; + +o_merid : /* NULL */ { + $$ = MER24; + } + | tMERIDIAN { + $$ = $1; + } + ; + +%% + +/* Month and day table. */ +static TABLE MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + /* The value of the day isn't used... */ + { "sunday", tDAY, 0 }, + { "monday", tDAY, 0 }, + { "tuesday", tDAY, 0 }, + { "wednesday", tDAY, 0 }, + { "thursday", tDAY, 0 }, + { "friday", tDAY, 0 }, + { "saturday", tDAY, 0 }, +}; + +/* Time units table. */ +static TABLE UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "week", tSEC_UNIT, 7 * 24 * 60 * 60 }, + { "day", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { "hour", tSEC_UNIT, 60 * 60 }, + { "minute", tSEC_UNIT, 60 }, + { "min", tSEC_UNIT, 60 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, +}; + +/* Timezone table. */ +static TABLE TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal */ + { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */ + { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */ + { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */ + { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */ + { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */ + { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "mez", tZONE, -HOUR(1) }, /* Middle European */ + { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */ + { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */ + { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */ + { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ + { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ + { "cct", tZONE, -HOUR(8) }, /* China Coast */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard */ + { "kst", tZONE, -HOUR(9) }, /* Korean Standard */ + { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */ + { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */ + { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */ + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + + /* For completeness we include the following entries. */ +#if 0 + + /* Duplicate names. Either they conflict with a zone listed above + * (which is either more likely to be seen or just been in circulation + * longer), or they conflict with another zone in this section and + * we could not reasonably choose one over the other. */ + { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */ + { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */ + { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */ + { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */ + { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */ + { "cst", tZONE, HOUR( 5) }, /* Chile Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */ + { "ast", tZONE, HOUR( 5) }, /* Acre Standard */ + { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */ + { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */ + { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */ + { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */ + { "sst", tZONE, HOUR(11) }, /* Samoa Standard */ + { "ist", tZONE, -HOUR(2) }, /* Israel Standard */ + { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */ + { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */ + { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */ + { "cst", tZONE, -HOUR(8) }, /* China Standard */ + { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */ + { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */ + + /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ + { "wat", tZONE, -HOUR(1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard */ + { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad */ + { "it", tZONE, -(HOUR(3)+30) }, /* Iran */ + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ + { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */ + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ + { "nst", tZONE, -HOUR(7) }, /* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra */ + { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */ + { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */ + { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */ + { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */ +#endif /* 0 */ +}; + + + +static void +date_error(const char *s) +{ + s = s; /* ARGSUSED */ + /* NOTREACHED */ +} + + +static time_t +ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian) +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) + return -1; + if (Meridian == MER24) { + if (Hours < 0 || Hours > 23) + return -1; + } + else { + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + if (Meridian == MERpm) + Hours += 12; + } + return (Hours * 60L + Minutes) * 60L + Seconds; +} + + +static time_t +Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, + time_t Seconds, MERIDIAN Meridian, DSTMODE dst) +{ + static int DaysNormal[13] = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static int DaysLeap[13] = { + 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static int LeapYears[] = { + 1972, 1976, 1980, 1984, 1988, 1992, 1996, + 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036 + }; + int *yp; + int *mp; + time_t Julian; + int i; + time_t tod; + + /* Year should not be passed as a relative value, but absolute one. + so this should not happen, but just ensure it */ + if (Year < 0) + Year = -Year; + if (Year < 100) { + Year += 1900; + if (Year < EPOCH) + Year += 100; + } + for (mp = DaysNormal, yp = LeapYears; yp < ARRAY_END(LeapYears); yp++) + if (Year == *yp) { + mp = DaysLeap; + break; + } + if (Year < EPOCH || Year > END_OF_TIME + || Month < 1 || Month > 12 + /* NOSTRICT *//* conversion from long may lose accuracy */ + || Day < 1 || Day > mp[(int)Month]) + return -1; + + Julian = Day - 1 + (Year - EPOCH) * 365; + for (yp = LeapYears; yp < ARRAY_END(LeapYears); yp++, Julian++) + if (Year <= *yp) + break; + for (i = 1; i < Month; i++) + Julian += *++mp; + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + tod = Julian; + if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst)) + Julian -= DST_OFFSET * 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(time_t Start, time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60; +} + + +static time_t +RelativeMonth(time_t Start, time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12; + Year += 1900; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord(char *buff, int length) +{ + char *p; + const char *q; + TABLE *tp; + int c; + + p = buff; + c = p[0]; + + /* See if we have an abbreviation for a month. */ + if (length == 3 || (length == 4 && p[3] == '.')) + for (tp = MonthDayTable; tp < ARRAY_END(MonthDayTable); tp++) { + q = tp->name; + if (c == q[0] && p[1] == q[1] && p[2] == q[2]) { + yylval.Number = tp->value; + return tp->type; + } + } + else + for (tp = MonthDayTable; tp < ARRAY_END(MonthDayTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Try for a timezone. */ + for (tp = TimezoneTable; tp < ARRAY_END(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Try the units table. */ + for (tp = UnitsTable; tp < ARRAY_END(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + if (--length > 0 && p[length] == 's') { + p[length] = '\0'; + for (tp = UnitsTable; tp < ARRAY_END(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + p[length] = 's'; + yylval.Number = tp->value; + return tp->type; + } + p[length] = 's'; + } + length++; + + /* Drop out any periods. */ + for (p = buff, q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + *p = '\0'; + + /* Try the meridians. */ + if (buff[1] == 'm' && buff[2] == '\0') { + if (buff[0] == 'a') { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (buff[0] == 'p') { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + } + + /* If we saw any periods, try the timezones again. */ + if (p - buff != length) { + c = buff[0]; + for (p = buff, tp = TimezoneTable; tp < ARRAY_END(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Unknown word -- assume GMT timezone. */ + yylval.Number = 0; + return tZONE; +} + + +static int +date_lex(void) +{ + char c; + char *p; + char buff[20]; + int sign; + int i; + int nesting; + + for ( ; ; ) { + /* Get first character after the whitespace. */ + for ( ; ; ) { + while (CTYPE(isspace, (int)*yyInput)) + yyInput++; + c = *yyInput; + + /* Ignore RFC 822 comments, typically time zone names. */ + if (c != LPAREN) + break; + for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; ) + if (c == LPAREN) + nesting++; + else if (!IS7BIT(c) || c == '\0' || c == '\r' + || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c)))) + /* Lexical error: bad comment. */ + return '?'; + yyInput++; + } + + /* A number? */ + if (CTYPE(isdigit, (int)c) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + yyInput++; + if (!CTYPE(isdigit, (int)*yyInput)) + /* Skip the plus or minus sign. */ + continue; + } + else + sign = 0; + for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, (int)c); ) + i = 10 * i + c - '0'; + yyInput--; + yylval.Number = sign < 0 ? -i : i; + return sign ? tSNUMBER : tUNUMBER; + } + + /* A word? */ + if (CTYPE(isalpha, (int)c)) { + for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, (int)c); ) + if (p < &buff[sizeof buff - 1]) + *p++ = CTYPE(isupper, (int)c) ? tolower(c) : c; + *p = '\0'; + yyInput--; + return LookupWord(buff, p - buff); + } + + return *yyInput++; + } +} + + +time_t +parsedate(char *p) +{ + time_t now; + struct tm *tm; + time_t Start; + + now = time(NULL); + yyInput = p; + + tm = gmtime(&now); + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = 0; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveRel = 0; + yyHaveTime = 0; + + if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1) + return -1; + + if (yyHaveDate || yyHaveTime) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now; + if (!yyHaveRel) + Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec; + } + + Start += yyRelSeconds; + if (yyRelMonth) + Start += RelativeMonth(Start, yyRelMonth); + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +#if YYDEBUG +extern int yydebug; +#endif /* YYDEBUG */ + +/* ARGSUSED */ +int +main(int ac, char *av[]) +{ + char buff[128]; + time_t d; + +#if YYDEBUG + yydebug = 1; +#endif /* YYDEBUG */ + + printf("Enter date, or blank line to exit.\n\t> "); + for ( ; ; ) { + printf("\t> "); + fflush(stdout); + if (gets(buff) == NULL || buff[0] == '\n') + break; +#if YYDEBUG + if (strcmp(buff, "yydebug") == 0) { + yydebug = !yydebug; + printf("yydebug = %s\n", yydebug ? "on" : "off"); + continue; + } +#endif /* YYDEBUG */ + d = parsedate(buff); + if (d == -1) + printf("Bad format - couldn't convert.\n"); + else + printf("%s", ctime(&d)); + } + + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ diff --git a/Src/pgp.c b/Src/pgp.c @@ -0,0 +1,494 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + OpenPGP messages + $Id: pgp.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#ifdef USE_PGP +#include "pgp.h" +#include <ctype.h> +#include <string.h> + +int pgp_decrypt(BUFFER *in, BUFFER *pass, BUFFER *sig, char *pubring, + char *secring) +{ + BUFFER *key; + int err; + + key = buf_new(); + if (pass) + buf_set(key, pass); + if (!pgp_ispacket(in)) + pgp_dearmor(in, in); + err = pgp_getmsg(in, key, sig, pubring, secring); + buf_free(key); + return (err); +} + +static void appendaddr(BUFFER *to, BUFFER *addr) +{ + if (bufifind(addr, "<")) { + for (addr->ptr = 0; addr->ptr < addr->length; addr->ptr++) + if (addr->data[addr->ptr] == '<') { + buf_rest(to, addr); + break; + } + } else { + buf_appendc(to, '<'); + buf_cat(to, addr); + buf_appendc(to, '>'); + } + buf_nl(to); + buf_clear(addr); +} + +int pgp_mailenc(int mode, BUFFER *msg, char *sigid, + BUFFER *pass, char *pubring, char *secring) +{ + BUFFER *hdr, *body, *line, *uid, *field, *content; + int err = -1; + + hdr = buf_new(); + body = buf_new(); + line = buf_new(); + uid = buf_new(); + field = buf_new(); + content = buf_new(); + + buf_appendc(uid, '<'); + buf_appends(uid, sigid); + if (sigid[strlen(sigid) - 1] != '@') + buf_appendc(uid, '>'); + + while (buf_getline(msg, line) == 0) + buf_cat(hdr, line), buf_nl(hdr); + + if ((mode & PGP_SIGN) && !(mode & PGP_ENCRYPT)) + while (buf_getheader(hdr, field, content) == 0) + if (bufileft(field, "content-") || bufieq(field, "mime-version")) { + /* Is MIME message */ + err = pgpmime_sign(msg, uid, pass, secring); + goto end; + } + + buf_rest(body, msg); + + if ((mode & PGP_SIGN) && !(mode & PGP_ENCRYPT)) { + err = pgp_signtxt(body, uid, pass, secring, mode & PGP_REMAIL); + } + + if (mode & PGP_ENCRYPT) { + BUFFER *plainhdr, *encrhdr, *to, *addr; + int encapsulate = 0; + + plainhdr = buf_new(); + encrhdr = buf_new(); + to = buf_new(); + addr = buf_new(); + while (buf_getheader(hdr, field, content) == 0) { + if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) { + buf_appendheader(plainhdr, field, content); + rfc822_addr(content, addr); + while (buf_getline(addr, content) != -1) + appendaddr(to, content); + } else + buf_appendheader(encrhdr, field, content); + } +#if 1 + /* encrypt the headers */ + buf_appends(plainhdr, "Subject: PGP encrypted message\n"); + if (encrhdr->length) { + buf_nl(encrhdr); + buf_cat(encrhdr, body); + buf_move(body, encrhdr); + encapsulate = 1; + } +#else /* end of 1 */ + /* send headers as plain text */ + buf_cat(plainhdr, encrhdr); +#endif /* not 1 */ + buf_move(hdr, plainhdr); + + buf_clear(line); + if (encapsulate) + buf_sets(line, "Content-Type: message/rfc822\n"); + else if (strlen(DEFLTENTITY)) + buf_setf(line, "Content-Type: %s\n", DEFLTENTITY); + buf_nl(line); + buf_cat(line, body); + buf_move(body, line); + + /* Use the user keyring if pubring == NULL */ + err = pgp_encrypt(mode, body, to, uid, pass, + pubring ? pubring : PGPPUBRING, secring); + buf_free(plainhdr); + buf_free(encrhdr); + buf_free(to); + buf_free(addr); + } + if (err == 0) { + if (mode & PGP_ENCRYPT) { +#if 1 + buf_sets(field, "+--"); +#else /* end of 1 */ + buf_setrnd(mboundary, 18); + encode(mboundary, 0); +#endif /* else if not 1 */ + + buf_appendf(hdr, + "Content-Type: multipart/encrypted; boundary=\"%b\"; " + "protocol=\"application/pgp-encrypted\"\n\n" + "--%b\n" + "Content-Type: application/pgp-encrypted\n\n" + "Version: 1\n\n" + "--%b\n" + "Content-Type: application/octet-stream\n", + field, field, field); + buf_appendf(body, "\n--%b--\n", field); + } + buf_move(msg, hdr); + buf_nl(msg); + buf_cat(msg, body); + } + end: + buf_free(hdr); + buf_free(body); + buf_free(line); + buf_free(uid); + buf_free(field); + buf_free(content); + return (err); +} + +static void pgp_setkey(BUFFER *key, int algo) +{ + buf_setc(key, algo); + buf_appendrnd(key, pgp_keylen(algo)); +} + +int pgp_encrypt(int mode, BUFFER *in, BUFFER *to, BUFFER *sigid, + BUFFER *pass, char *pubring, char *secring) +{ + BUFFER *dek, *out, *sig, *dest, *tmp; + int err = 0, sym = PGP_K_ANY, mdc = 0; + int text; + + out = buf_new(); + tmp = buf_new(); + dek = buf_new(); + sig = buf_new(); + dest = buf_new(); + + text = mode & PGP_TEXT ? 1 : 0; + + if (mode & (PGP_CONV3DES | PGP_CONVCAST)) + mode |= PGP_NCONVENTIONAL; + + if (mode & PGP_SIGN) { + err = pgp_sign(in, NULL, sig, sigid, pass, text, 0, 0, + mode & PGP_REMAIL ? 1 : 0, NULL, secring); + if (err < 0) + goto end; + if (mode & PGP_DETACHEDSIG) { + buf_move(in, sig); + if (!(mode & PGP_NOARMOR)) + pgp_armor(in, PGP_ARMOR_NYMSIG); + goto end; + } + } + if (mode & PGP_ENCRYPT) { + err = buf_getline(to, dest); + if (err == -1) + goto end; + if (to->ptr == to->length) { + if ((err = pgpdb_getkey(PK_ENCRYPT, PGP_ANY, &sym, &mdc, NULL, NULL, dest, NULL, + NULL, pubring, NULL)) < 0) + goto end; + pgp_setkey(dek, sym); + err = pgp_sessionkey(out, dest, NULL, dek, pubring); +#ifdef USE_IDEA + if (err < 0 && dek->data[0] == PGP_K_IDEA) { + pgp_setkey(dek, PGP_K_3DES); + err = pgp_sessionkey(out, dest, NULL, dek, pubring); + } +#endif /* USE_IDEA */ + } else { + /* multiple recipients */ + pgp_setkey(dek, PGP_K_3DES); + buf_rewind(to); + while (buf_getline(to, dest) != -1) + if (dest->length) { + err = pgp_sessionkey(tmp, dest, NULL, dek, pubring); +#ifdef USE_IDEA + if (err < 0 && dek->data[0] != PGP_K_IDEA) { + buf_rewind(to); + buf_clear(out); + pgp_setkey(dek, PGP_K_IDEA); + continue; + } +#endif /* USE_IDEA */ + if (err < 0) + goto end; + buf_cat(out, tmp); + } + } + } else if (mode & PGP_NCONVENTIONAL) { + /* genereate DEK in pgp_symsessionkey */ + buf_setc(dek, mode & PGP_CONVCAST ? PGP_K_CAST5 : PGP_K_3DES); + pgp_marker(out); + err = pgp_symsessionkey(tmp, dek, to); + buf_cat(out, tmp); + } else if (mode & PGP_CONVENTIONAL) { + digest_md5(to, tmp); + buf_setc(dek, PGP_K_IDEA); + buf_cat(dek, tmp); + } + + pgp_literal(in, NULL, text); + if (sig->length) { + buf_cat(sig, in); + buf_move(in, sig); + } + pgp_compress(in); + if (mode & (PGP_ENCRYPT | PGP_CONVENTIONAL | PGP_NCONVENTIONAL)) + pgp_symmetric(in, dek, mdc); + if (mode & (PGP_ENCRYPT | PGP_NCONVENTIONAL)) { + buf_cat(out, in); + buf_move(in, out); + } + if (!(mode & PGP_NOARMOR)) + pgp_armor(in, (mode & PGP_REMAIL) ? PGP_ARMOR_REM : PGP_ARMOR_NORMAL); + +end: + buf_free(out); + buf_free(tmp); + buf_free(dek); + buf_free(sig); + buf_free(dest); + return (err); +} + +#define POLY 0X1864CFB + +unsigned long crc24(BUFFER * in) +{ + unsigned long crc = 0xB704CE; + long p; + int i; + +#if 0 + /* CRC algorithm from RFC 2440 */ + for (p = 0; p < in->length; p++) { + crc ^= in->data[p] << 16; + for (i = 0; i < 8; i++) { + crc <<= 1; + if (crc & 0x1000000) + crc ^= POLY; + } + } +#else + /* pre-computed CRC table -- much faster */ + unsigned long table[256]; + unsigned long t; + int q = 0; + + table[0] = 0; + for (i = 0; i < 128; i++) { + t = table[i] << 1; + if (t & 0x1000000) { + table[q++] = t ^ POLY; + table[q++] = t; + } else { + table[q++] = t; + table[q++] = t ^ POLY; + } + } + for (p = 0; p < in->length; p++) + crc = crc << 8 ^ table[(in->data[p] ^ crc >> 16) & 255]; +#endif + return crc & ((1<<24)-1); +} + +/* ASCII armor */ + +int pgp_dearmor(BUFFER *in, BUFFER *out) +{ + BUFFER *line, *temp; + int err = 0; + int tempbuf = 0; + unsigned long crc1, crc2; + + line = buf_new(); + temp = buf_new(); + + if (in == out) { + out = buf_new(); + tempbuf = 1; + } + do + if (buf_getline(in, line) == -1) { + err = -1; + goto end; + } + while (!bufleft(line, begin_pgp)) ; + + while (buf_getheader(in, temp, line) == 0) ; /* scan for empty line */ + + err = decode(in, out); + crc1 = crc24(out); + err = buf_getline(in, line); + if (line->length == 5 && line->data[0] == '=') { /* CRC */ + line->ptr = 1; + err = decode(line, temp); + crc2 = (((unsigned long)temp->data[0])<<16) | (((unsigned long)temp->data[1])<<8) | temp->data[2]; + if (crc1 == crc2) + err = buf_getline(in, line); + else { + errlog(NOTICE, "Message CRC does not match.\n"); + err = -1; + } + } else + err = -1; + if (err == 0 && bufleft(line, end_pgp)) + err = 0; + else + err = -1; + +end: + buf_free(temp); + buf_free(line); + + if (tempbuf) { + buf_move(in, out); + buf_free(out); + } + return (err); +} + +int pgp_armor(BUFFER *in, int mode) + +/* mode = 1: remailer message (PGP_ARMOR_REM) + * 0: normal message, (PGP_ARMOR_NORMAL) + * 2: key (PGP_ARMOR_KEY) + * 3: nym key (PGP_ARMOR_NYMKEY) + * 4: nym signature (PGP_ARMOR_NYMSIG) + * 5: secret key (PGP_ARMOR_SECKEY) + */ + +{ + BUFFER *out; + unsigned long crc; + + crc = crc24(in); + encode(in, 64); + + out = buf_new(); + if (mode == PGP_ARMOR_KEY || mode == PGP_ARMOR_NYMKEY) + buf_sets(out, begin_pgpkey); + else if (mode == PGP_ARMOR_NYMSIG) + buf_sets(out, begin_pgpsig); + else if (mode == PGP_ARMOR_SECKEY) + buf_sets(out, begin_pgpseckey); + else + buf_sets(out, begin_pgpmsg); + buf_nl(out); +#ifdef CLOAK + if (mode == PGP_ARMOR_REM || mode == PGP_ARMOR_NYMKEY || mode == PGP_ARMOR_NYMSIG) + buf_appends(out, "Version: N/A\n"); + else +#elif MIMIC /* end of CLOAK */ + if (mode == PGP_ARMOR_REM || mode == PGP_ARMOR_NYMKEY || mode == PGP_ARMOR_NYMSIG) + buf_appends(out, "Version: 2.6.3i\n"); + else +#endif /* MIMIC */ + { + buf_appends(out, "Version: Mixmaster "); + buf_appends(out, VERSION); + buf_appends(out, " (OpenPGP module)\n"); + } + buf_nl(out); + buf_cat(out, in); + buf_reset(in); + buf_appendc(in, (crc >> 16) & 255); + buf_appendc(in, (crc >> 8) & 255); + buf_appendc(in, crc & 255); + encode(in, 0); + buf_appendc(out, '='); + buf_cat(out, in); + buf_nl(out); + if (mode == PGP_ARMOR_KEY || mode == PGP_ARMOR_NYMKEY) + buf_appends(out, end_pgpkey); + else if (mode == PGP_ARMOR_NYMSIG) + buf_appends(out, end_pgpsig); + else if (mode == PGP_ARMOR_SECKEY) + buf_appends(out, end_pgpseckey); + else + buf_appends(out, end_pgpmsg); + buf_nl(out); + + buf_move(in, out); + buf_free(out); + return (0); +} + +int pgp_keygen(int algo, int bits, BUFFER *userid, BUFFER *pass, char *pubring, + char *secring, int remail) +{ + switch (algo) { + case PGP_ES_RSA: +#ifndef USE_IDEA + errlog(WARNING, "IDEA disabled: OpenPGP RSA key cannot be used for decryption!\n"); +#endif + return (pgp_rsakeygen(bits, userid, pass, pubring, secring, remail)); + case PGP_E_ELG: + return (pgp_dhkeygen(bits, userid, pass, pubring, secring, remail)); + default: + return -1; + } +} + +int pgp_signtxt(BUFFER *msg, BUFFER *uid, BUFFER *pass, + char *secring, int remail) +{ + int err; + BUFFER *line, *sig, *out; + + sig = buf_new(); + out = buf_new(); + line = buf_new(); + + buf_appends(out, begin_pgpsigned); + buf_nl(out); + if (pgpdb_getkey(PK_SIGN, PGP_ANY, NULL, NULL, NULL, NULL, uid, NULL, NULL, secring, pass) == PGP_S_DSA) + buf_appends(out, "Hash: SHA1\n"); + buf_nl(out); + while (buf_getline(msg, line) != -1) { + if (line->data[0] == '-') + buf_appends(out, "- "); + buf_cat(out, line); + buf_nl(out); + } + buf_nl(out); + + buf_rewind(msg); + err = pgp_encrypt(PGP_SIGN | PGP_DETACHEDSIG | PGP_TEXT | + (remail ? PGP_REMAIL : 0), + msg, NULL, uid, pass, NULL, secring); + if (err == -1) + goto end; + buf_cat(out, msg); + buf_move(msg, out); +end: + buf_free(line); + buf_free(sig); + buf_free(out); + return (err); +} + +#endif /* USE_PGP */ diff --git a/Src/pgp.h b/Src/pgp.h @@ -0,0 +1,189 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + OpenPGP messages + $Id: pgp.h 934 2006-06-24 13:40:39Z rabbi $ */ + + +#ifdef USE_PGP +#ifndef _PGP_H +#include "mix3.h" +#ifdef USE_OPENSSL +#include <openssl/opensslv.h> +#endif /* USE_OPENSSL */ + +/* in the PGP Version header, list the same information as all other + versions of Mixmaster to prevent anonymity set division. */ +#define CLOAK + +/* try to make the messages look similar to PGP 2.6.3i output + (compression is not always the same though). */ +#define MIMIC + +/* packet types */ +#define PGP_SESKEY 1 +#define PGP_SIG 2 +#define PGP_SYMSESKEY 3 +#define PGP_OSIG 4 +#define PGP_SECKEY 5 +#define PGP_PUBKEY 6 +#define PGP_SECSUBKEY 7 +#define PGP_COMPRESSED 8 +#define PGP_ENCRYPTED 9 +#define PGP_MARKER 10 +#define PGP_LITERAL 11 +#define PGP_TRUST 12 +#define PGP_USERID 13 +#define PGP_PUBSUBKEY 14 +#define PGP_ENCRYPTEDMDC 18 +#define PGP_MDC 19 + +/* symmetric algorithms */ +#define PGP_K_ANY 0 +#define PGP_K_IDEA 1 +#define PGP_K_3DES 2 +#define PGP_K_CAST5 3 +#define PGP_K_BF 4 +#define PGP_K_AES128 7 +#define PGP_K_AES192 8 +#define PGP_K_AES256 9 + +/* hash algorithms */ +#define PGP_H_MD5 1 +#define PGP_H_SHA1 2 +#define PGP_H_RIPEMD 3 + +/* signature types */ +#define PGP_SIG_BINARY 0 +#define PGP_SIG_CANONIC 1 +#define PGP_SIG_CERT 0x10 +#define PGP_SIG_CERT1 0x11 +#define PGP_SIG_CERT2 0x12 +#define PGP_SIG_CERT3 0x13 +#define isPGP_SIG_CERT(x) (x >= PGP_SIG_CERT && x <= PGP_SIG_CERT3) +#define PGP_SIG_BINDSUBKEY 0x18 +#define PGP_SIG_KEYREVOKE 0x20 +#define PGP_SIG_SUBKEYREVOKE 0x28 +#define PGP_SIG_CERTREVOKE 0x30 + +/* signature subpacket types */ +#define PGP_SUB_CREATIME 2 +#define PGP_SUB_CERTEXPIRETIME 3 +#define PGP_SUB_KEYEXPIRETIME 9 +#define PGP_SUB_PSYMMETRIC 11 +#define PGP_SUB_ISSUER 16 +#define PGP_SUB_PRIMARY 25 +#define PGP_SUB_FEATURES 30 + +#define ARMORED 1 + +/* publick key algorithm operation modes */ + +#define PK_ENCRYPT 1 +#define PK_DECRYPT 2 +#define PK_SIGN 3 +#define PK_VERIFY 4 + +#define MD5PREFIX "\x30\x20\x30\x0C\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02\x05\x05\x00\x04\x10" +#define SHA1PREFIX "\x30\x21\x30\x09\x06\x05\x2b\x0E\x03\x02\x1A\x05\x00\x04\x14" + +typedef struct { + int ok; + BUFFER *userid; + byte sigtype; + long sigtime; + byte hash[16]; +} pgpsig; + +/* internal error codes */ +#define PGP_SIGVRFY 99 /* valid signature packet to be verified */ + +/* pgpdata.c */ +int pgp_getsk(BUFFER *p, BUFFER *pass, BUFFER *key); +int pgp_makesk(BUFFER *out, BUFFER *key, int sym, int type, int hash, + BUFFER *pass); +void pgp_iteratedsk(BUFFER *salted, BUFFER *salt, BUFFER *pass, byte c); +int pgp_expandsk(BUFFER *key, int skalgo, int hashalgo, BUFFER *data); +int skcrypt(BUFFER *data, int skalgo, BUFFER *key, BUFFER *iv, int enc); +int mpi_get(BUFFER *buf, BUFFER *mpi); +int mpi_put(BUFFER *buf, BUFFER *mpi); +int pgp_rsa(BUFFER *buf, BUFFER *key, int mode); +void pgp_sigcanonic(BUFFER *msg); +int pgp_makepubkey(BUFFER *seckey, BUFFER *outtxt, BUFFER *pubkey, + BUFFER *pass, int keyalgo); +int pgp_makekeyheader(int type, BUFFER *keypacket, BUFFER *outtxt, + BUFFER *pass, int keyalgo); +int pgp_getkey(int mode, int algo, int *sym, int *mdc, long *expires, BUFFER *keypacket, BUFFER *key, + BUFFER *keyid, BUFFER *userid, BUFFER *pass); +int pgp_rsakeygen(int bits, BUFFER *userid, BUFFER *pass, char *pubring, + char *secring, int remail); +int pgp_dhkeygen(int bits, BUFFER *userid, BUFFER *pass, char *pubring, + char *secring, int remail); +int pgp_dosign(int algo, BUFFER *data, BUFFER *key); +int pgp_elgencrypt(BUFFER *b, BUFFER *key); +int pgp_elgdecrypt(BUFFER *b, BUFFER *key); +int pgp_keyid(BUFFER *key, BUFFER *id); +int pgp_keylen(int symalgo); +int pgp_blocklen(int symalgo); + +/* pgpget.c */ +int pgp_getmsg(BUFFER *in, BUFFER *key, BUFFER *sig, char *pubring, + char *secring); +int pgp_ispacket(BUFFER *buf); +int pgp_isconventional(BUFFER *buf); +int pgp_packettype(BUFFER *buf, long *len, int *partial); +int pgp_packetpartial(BUFFER *buf, long *len, int *partial); +int pgp_getpacket(BUFFER *buf, BUFFER *p); +int pgp_getsig(BUFFER *p, pgpsig *sig, char *pubring); +void pgp_verify(BUFFER *msg, BUFFER *detached, pgpsig *sig); +int pgp_getsymmetric(BUFFER *buf, BUFFER *key, int algo, int type); +int pgp_getliteral(BUFFER *buf); +int pgp_uncompress(BUFFER *buf); +int pgp_getsessionkey(BUFFER *buf, BUFFER *pass, char *secring); +int pgp_getsymsessionkey(BUFFER *buf, BUFFER *pass); + +/* pgpcreat.c */ +int pgp_packet(BUFFER *buf, int type); +int pgp_packet3(BUFFER *buf, int type); +int pgp_symmetric(BUFFER *buf, BUFFER *key, int mdc); +int pgp_literal(BUFFER *buf, char *filename, int text); +int pgp_compress(BUFFER *buf); +int pgp_sessionkey(BUFFER *buf, BUFFER *user, BUFFER *keyid, BUFFER *seskey, + char *pubring); +void pgp_marker(BUFFER *buf); +int pgp_symsessionkey(BUFFER *buf, BUFFER *seskey, BUFFER *pass); +int pgp_sign(BUFFER *msg, BUFFER *msg2, BUFFER *sig, BUFFER *userid, + BUFFER *pass, int type, int self, long now, int remail, + BUFFER *seckey, char *secring); +int pgp_digest(int hashalgo, BUFFER *in, BUFFER *d); + +/* pgpdb.c */ + +int pgpdb_getkey(int mode, int algo, int *sym, int *mdc, long *expires, BUFFER *key, BUFFER *user, + BUFFER *founduid, BUFFER *keyid, char *keyring, BUFFER *pass); + +typedef struct { + int filetype; + BUFFER *db; + LOCK *lock; + int modified; + int type; /* undefined, public, private */ + char filename[LINELEN]; + BUFFER *encryptkey; +#ifndef NDEBUG + int writer; +#endif +} KEYRING; + +KEYRING *pgpdb_new(char *keyring, int filetype, BUFFER *encryptkey, int type); +KEYRING *pgpdb_open(char *keyring, BUFFER *encryptkey, int writer, int type); +int pgpdb_append(KEYRING *keydb, BUFFER *p); +int pgpdb_getnext(KEYRING *keydb, BUFFER *p, BUFFER *keyid, BUFFER *userid); +int pgpdb_close(KEYRING *keydb); + +#endif /* not _PGP_H */ +#endif /* USE_PGP */ diff --git a/Src/pgpcreat.c b/Src/pgpcreat.c @@ -0,0 +1,848 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Create OpenPGP packets + $Id: pgpcreat.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#ifdef USE_PGP +#include "pgp.h" +#include "crypto.h" +#include <assert.h> +#include <time.h> +#include <string.h> + +int pgp_packet(BUFFER *in, int type) +{ + int ctb; + BUFFER *out; + + out = buf_new(); + if (type > 15) { + ctb = 0xC0 | type; /* make v4 packet */ + buf_setc(out, ctb); + if (in->length > 8383) { + buf_appendc(out, 0xFF); + buf_appendl(out, in->length); + } else if (in->length > 191) { +#if 0 + buf_appendc(out, ((in->length-192) >> 8) + 192); + buf_appendc(out, (in->length-192) & 0xFF); +#else /* end of 0 */ + buf_appendi(out, in->length - 0xC0 + 0xC000); +#endif /* else if not 0 */ + } else { + buf_appendc(out, in->length); + } + } else { + ctb = 128 + (type << 2); + if (in->length < 256 && type != PGP_PUBKEY && type != PGP_SECKEY && + type != PGP_SIG && type != PGP_PUBSUBKEY && type != PGP_SECSUBKEY +#ifdef MIMIC + && type != PGP_ENCRYPTED +#endif /* MIMIC */ + ) { + buf_setc(out, ctb); + buf_appendc(out, in->length); + } +#ifndef MIMIC + else if (in->length < 65536) +#else /* end of not MIMIC */ + else if ((type == PGP_PUBKEY || type == PGP_SECKEY || type == PGP_SIG + || type == PGP_SESKEY || type == PGP_PUBSUBKEY || + type == PGP_SECSUBKEY) && in->length < 65536) +#endif /* else if MIMIC */ + { + buf_appendc(out, ctb | 1); + buf_appendi(out, in->length); + } else { + buf_appendc(out, ctb | 2); + buf_appendl(out, in->length); + } + } + buf_cat(out, in); + buf_move(in, out); + buf_free(out); + return (0); +} + +int pgp_subpacket(BUFFER *in, int type) +{ + BUFFER *out; + int len; + + out = buf_new(); + len = in->length + 1; + if (len < 192) + buf_setc(out, len); + else { + buf_setc(out, 255); + buf_appendl(out, len); + } + buf_appendc(out, type); + buf_cat(out, in); + buf_move(in, out); + buf_free(out); + return (0); +} + +int pgp_packet3(BUFFER *in, int type) +{ +#ifdef MIMIC + int ctb; + BUFFER *out; + + out = buf_new(); + ctb = 128 + (type << 2); + buf_setc(out, ctb | 3); + buf_cat(out, in); + buf_move(in, out); + buf_free(out); + return (0); +#else /* end of MIMIC */ + return pgp_packet(in, type); +#endif /* else if not MIMIC */ +} + +#ifdef USE_IDEA +static int pgp_ideaencrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + byte iv[8]; + int i, n = 0; + IDEA_KEY_SCHEDULE ks; + SHA_CTX c; + + assert(key->length == 17); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + idea_set_encrypt_key(key->data + 1, &ks); + + if (mdc) { + mdc = 1; + out->data[0] = 1; + } + rnd_bytes(out->data + mdc, 8); + out->data[8 + mdc] = out->data[6 + mdc], out->data[9 + mdc] = out->data[7 + mdc]; + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, out->data + 1, 10); + SHA1_Update(&c, in->data, in->length); + } + n = 0; + idea_cfb64_encrypt(out->data + mdc, out->data + mdc, 10, &ks, iv, &n, IDEA_ENCRYPT); + if (!mdc) { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, out->data + 2, 6); + n = 0; + } + idea_cfb64_encrypt(in->data, out->data + 10 + mdc, in->length, &ks, iv, &n, + IDEA_ENCRYPT); + if (mdc) { + SHA1_Update(&c, "\xD3\x14", 2); /* 0xD3 = 0xC0 | PGP_MDC */ + idea_cfb64_encrypt("\xD3\x14", out->data + 11 + in->length, 2, &ks, iv, &n, + IDEA_ENCRYPT); + SHA1_Final(out->data + 13 + in->length, &c); + idea_cfb64_encrypt(out->data + 13 + in->length, out->data + 13 + in->length, 20, &ks, iv, &n, + IDEA_ENCRYPT); + } + return (0); +} +#endif /* USE_IDEA */ + +static int pgp_3desencrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + des_cblock iv; + int i, n = 0; + des_key_schedule ks1; + des_key_schedule ks2; + des_key_schedule ks3; + SHA_CTX c; + + assert(key->length == 25); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + des_set_key((const_des_cblock *) (key->data + 1), ks1); + des_set_key((const_des_cblock *) (key->data + 9), ks2); + des_set_key((const_des_cblock *) (key->data+ 17), ks3); + + if (mdc) { + mdc = 1; + out->data[0] = 1; + } + rnd_bytes(out->data + mdc, 8); + out->data[8 + mdc] = out->data[6 + mdc], out->data[9 + mdc] = out->data[7 + mdc]; + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, out->data + 1, 10); + SHA1_Update(&c, in->data, in->length); + } + n = 0; + des_ede3_cfb64_encrypt(out->data + mdc, out->data + mdc, 10, ks1, ks2, ks3, &iv, &n, + ENCRYPT); + if (!mdc) { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, out->data + 2, 6); + n = 0; + } + des_ede3_cfb64_encrypt(in->data, out->data + 10 + mdc, in->length, ks1, ks2, ks3, + &iv, &n, ENCRYPT); + if (mdc) { + SHA1_Update(&c, "\xD3\x14", 2); /* 0xD3 = 0xC0 | PGP_MDC */ + des_ede3_cfb64_encrypt("\xD3\x14", out->data + 11 + in->length, 2, ks1, ks2, ks3, + &iv, &n, ENCRYPT); + SHA1_Final(out->data + 13 + in->length, &c); + des_ede3_cfb64_encrypt(out->data + 13 + in->length, out->data + 13 + in->length, 20, ks1, ks2, ks3, + &iv, &n, ENCRYPT); + } + return (0); +} + +static int pgp_castencrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + byte iv[8]; + int i, n = 0; + CAST_KEY ks; + SHA_CTX c; + + assert(key->length == 17); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + CAST_set_key(&ks, 16, key->data + 1); + + if (mdc) { + mdc = 1; + out->data[0] = 1; + } + rnd_bytes(out->data + mdc, 8); + out->data[8 + mdc] = out->data[6 + mdc], out->data[9 + mdc] = out->data[7 + mdc]; + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, out->data + 1, 10); + SHA1_Update(&c, in->data, in->length); + } + n = 0; + CAST_cfb64_encrypt(out->data + mdc, out->data + mdc, 10, &ks, iv, &n, CAST_ENCRYPT); + if (!mdc) { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, out->data + 2, 6); + n = 0; + } + CAST_cfb64_encrypt(in->data, out->data + 10 + mdc, in->length, &ks, iv, &n, + CAST_ENCRYPT); + if (mdc) { + SHA1_Update(&c, "\xD3\x14", 2); /* 0xD3 = 0xC0 | PGP_MDC */ + CAST_cfb64_encrypt("\xD3\x14", out->data + 11 + in->length, 2, &ks, iv, &n, + CAST_ENCRYPT); + SHA1_Final(out->data + 13 + in->length, &c); + CAST_cfb64_encrypt(out->data + 13 + in->length, out->data + 13 + in->length, 20, &ks, iv, &n, + CAST_ENCRYPT); + } + return (0); +} + +static int pgp_bfencrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + byte iv[8]; + int i, n = 0; + BF_KEY ks; + SHA_CTX c; + + assert(key->length == 17); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + BF_set_key(&ks, 16, key->data + 1); + + if (mdc) { + mdc = 1; + out->data[0] = 1; + } + rnd_bytes(out->data + mdc, 8); + out->data[8 + mdc] = out->data[6 + mdc], out->data[9 + mdc] = out->data[7 + mdc]; + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, out->data + 1, 10); + SHA1_Update(&c, in->data, in->length); + } + n = 0; + BF_cfb64_encrypt(out->data + mdc, out->data + mdc, 10, &ks, iv, &n, BF_ENCRYPT); + if (!mdc) { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, out->data + 2, 6); + n = 0; + } + BF_cfb64_encrypt(in->data, out->data + 10 + mdc, in->length, &ks, iv, &n, + BF_ENCRYPT); + if (mdc) { + SHA1_Update(&c, "\xD3\x14", 2); /* 0xD3 = 0xC0 | PGP_MDC */ + BF_cfb64_encrypt("\xD3\x14", out->data + 11 + in->length, 2, &ks, iv, &n, + BF_ENCRYPT); + SHA1_Final(out->data + 13 + in->length, &c); + BF_cfb64_encrypt(out->data + 13 + in->length, out->data + 13 + in->length, 20, &ks, iv, &n, + BF_ENCRYPT); + } + return (0); +} + +#ifdef USE_AES +static int pgp_aesencrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + byte iv[16]; + int i, n = 0; + AES_KEY ks; + SHA_CTX c; + + assert(key->length == 17 || key->length == 25 || key->length == 33); + + for (i = 0; i < 16; i++) + iv[i] = 0; + + AES_set_encrypt_key(key->data + 1, (key->length-1)<<3, &ks); + + if (mdc) { + mdc = 1; + out->data[0] = 1; + } + rnd_bytes(out->data + mdc, 16); + out->data[16 + mdc] = out->data[14 + mdc], out->data[17 + mdc] = out->data[15 + mdc]; + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, out->data + 1, 18); + SHA1_Update(&c, in->data, in->length); + } + n = 0; + AES_cfb128_encrypt(out->data + mdc, out->data + mdc, 18, &ks, iv, &n, AES_ENCRYPT); + if (!mdc) { + iv[14] = iv[0], iv[15] = iv[1]; + memcpy(iv, out->data + 2, 14); + n = 0; + } + AES_cfb128_encrypt(in->data, out->data + 18 + mdc, in->length, &ks, iv, &n, + AES_ENCRYPT); + if (mdc) { + SHA1_Update(&c, "\xD3\x14", 2); /* 0xD3 = 0xC0 | PGP_MDC */ + AES_cfb128_encrypt("\xD3\x14", out->data + 19 + in->length, 2, &ks, iv, &n, + AES_ENCRYPT); + SHA1_Final(out->data + 21 + in->length, &c); + AES_cfb128_encrypt(out->data + 21 + in->length, out->data + 21 + in->length, 20, &ks, iv, &n, + AES_ENCRYPT); + } + return (0); +} +#endif /* USE_AES */ + +int pgp_symmetric(BUFFER *in, BUFFER *key, int mdc) +{ + BUFFER *out; + int sym; + + out = buf_new(); + if (pgp_blocklen(sym = buf_getc(key)) > 8) + mdc = 1; /* force MDC for AES */ + buf_prepare(out, in->length + (mdc?(1+2+22):2) + pgp_blocklen(sym)); + switch (sym) { +#ifdef USE_IDEA + case PGP_K_IDEA: + pgp_ideaencrypt(in, out, key, mdc); + break; +#endif /* USE_IDEA */ +#ifdef USE_AES + case PGP_K_AES128: + case PGP_K_AES192: + case PGP_K_AES256: + pgp_aesencrypt(in, out, key, mdc); + break; +#endif /* USE_AES */ + case PGP_K_3DES: + pgp_3desencrypt(in, out, key, mdc); + break; + case PGP_K_CAST5: + pgp_castencrypt(in, out, key, mdc); + break; + case PGP_K_BF: + pgp_bfencrypt(in, out, key, mdc); + break; + default: + errlog(ERRORMSG, "Unknown symmetric algorithm.\n"); + } + pgp_packet(out, mdc?PGP_ENCRYPTEDMDC:PGP_ENCRYPTED); + + buf_move(in, out); + buf_free(out); + return (0); +} + +int pgp_literal(BUFFER *b, char *filename, int text) +{ + BUFFER *out; + BUFFER *line; + + if (filename == NULL) + filename = "stdin"; + + if (strlen(filename) > 255) + return (-1); + + out = buf_new(); + line = buf_new(); + + if (text) + buf_setc(out, 't'); + else + buf_setc(out, 'b'); + buf_appendc(out, strlen(filename)); + buf_appends(out, filename); + buf_appendl(out, 0); /* timestamp */ + + if (b->length > 0) { + if (text) + while (buf_getline(b, line) != -1) { + buf_cat(out, line); + buf_appends(out, "\r\n"); + } else + buf_cat(out, b); + } + pgp_packet(out, PGP_LITERAL); + buf_move(b, out); + buf_free(out); + buf_free(line); + + return (0); +} + +int pgp_compress(BUFFER *in) +{ + int err; + BUFFER *out; + + out = buf_new(); + buf_setc(out, 1); + err = buf_zip(out, in, 13); + if (err == 0) { + pgp_packet3(out, PGP_COMPRESSED); + buf_move(in, out); + } + buf_free(out); + return (err); +} + +int pgp_sessionkey(BUFFER *out, BUFFER *user, BUFFER *keyid, BUFFER *seskey, + char *pubring) +{ + BUFFER *encrypt, *key, *id; + int algo, sym, err = -1; + int i, csum = 0; + int tempbuf = 0; + + encrypt = buf_new(); + key = buf_new(); + id = buf_new(); + if (keyid == NULL) { + keyid = buf_new(); + tempbuf = 1; + } + sym = seskey->data[0]; + if ((algo = pgpdb_getkey(PK_ENCRYPT, PGP_ANY, &sym, NULL, NULL, key, user, NULL, keyid, + pubring, NULL)) == -1) + goto end; + + buf_setc(out, 3); /* type */ + buf_cat(out, keyid); + buf_appendc(out, algo); /* algorithm */ + + buf_set(encrypt, seskey); + + for (i = 1; i < encrypt->length; i++) + csum = (csum + encrypt->data[i]) % 65536; + buf_appendi(encrypt, csum); + + switch (algo) { + case PGP_ES_RSA: + err = pgp_rsa(encrypt, key, PK_ENCRYPT); + mpi_put(out, encrypt); + break; + case PGP_E_ELG: + err = pgp_elgencrypt(encrypt, key); + buf_cat(out, encrypt); + break; + default: + errlog(NOTICE, "Unknown encryption algorithm.\n"); + err = -1; + goto end; + } + if (err == -1) { + errlog(ERRORMSG, "Encryption failed!\n"); + goto end; + } + pgp_packet(out, PGP_SESKEY); +end: + if (tempbuf) + buf_free(keyid); + buf_free(id); + buf_free(encrypt); + buf_free(key); + return (err); +} + +void pgp_marker(BUFFER *out) +{ + buf_clear(out); + buf_append(out, "PGP", 3); + pgp_packet(out, PGP_MARKER); +} + +int pgp_symsessionkey(BUFFER *out, BUFFER *seskey, BUFFER *pass) +{ + BUFFER *key; + int sym; + key = buf_new(); + + sym = seskey->data[0]; + buf_setc(out, 4); /* version */ +#ifdef MIMICPGP5 + pgp_makesk(out, key, sym, 1, PGP_H_MD5, pass); +#else /* end of MIMICPGP5 */ + pgp_makesk(out, key, sym, 3, PGP_H_SHA1, pass); +#endif /* else if not MIMICPGP5 */ + if (seskey->length > 1) + buf_cat(out, seskey); + else { + buf_setc(seskey, sym); + buf_cat(seskey, key); + } + pgp_packet(out, PGP_SYMSESKEY); + buf_free(key); + return (0); +} + +int pgp_digest(int hashalgo, BUFFER *in, BUFFER *d) +{ + switch (hashalgo) { + case PGP_H_MD5: + digest_md5(in, d); + return (0); + case PGP_H_SHA1: + digest_sha1(in, d); + return (0); + case PGP_H_RIPEMD: + digest_rmd160(in, d); + return (0); + default: + return (-1); + } +} + +int asnprefix(BUFFER *b, int hashalgo) +{ + switch (hashalgo) { + case PGP_H_MD5: + buf_append(b, MD5PREFIX, sizeof(MD5PREFIX) - 1); + return (0); + case PGP_H_SHA1: + buf_append(b, SHA1PREFIX, sizeof(SHA1PREFIX) - 1); + return (0); + default: + return (-1); + } +} + +int pgp_expandsk(BUFFER *key, int skalgo, int hashalgo, BUFFER *data) +{ + BUFFER *temp; + int keylen; + int err = 0; + temp = buf_new(); + + keylen = pgp_keylen(skalgo); + buf_clear(key); + while (key->length < keylen) { + if (pgp_digest(hashalgo, data, temp) == -1) { + err = -1; + goto end; + } + buf_cat(key, temp); + + buf_setc(temp, 0); + buf_cat(temp, data); + buf_move(data, temp); + } + + if (key->length > keylen) { + buf_set(temp, key); + buf_get(temp, key, keylen); + } + end: + buf_free(temp); + return(err); +} + +int pgp_makesk(BUFFER *out, BUFFER *key, int sym, int type, int hash, + BUFFER *pass) +{ + int err = 0; + BUFFER *salted; + salted = buf_new(); + + buf_appendc(out, sym); + buf_appendc(out, type); + buf_appendc(out, hash); + switch (type) { + case 0: + buf_set(salted, pass); + break; + case 1: + buf_appendrnd(salted, 8); /* salt */ + buf_cat(out, salted); + buf_cat(salted, pass); + break; + case 3: + buf_appendrnd(salted, 8); /* salt */ + buf_cat(out, salted); + buf_appendc(out, 96); /* encoded count value 65536 */ + pgp_iteratedsk(salted, salted, pass, 96); + break; + default: + err = -1; + } + pgp_expandsk(key, sym, hash, salted); + buf_free(salted); + return (err); +} + +/* PGP/MIME needs to know the hash algorithm */ +int pgp_signhashalgo(BUFFER *algo, BUFFER *userid, char *secring, BUFFER *pass) +{ + int pkalgo; + + pkalgo = pgpdb_getkey(PK_SIGN, PGP_ANY, NULL, NULL, NULL, NULL, userid, NULL, NULL, + secring, pass); + if (pkalgo == PGP_S_DSA) + buf_sets(algo, "sha1"); + if (pkalgo == PGP_ES_RSA) + buf_sets(algo, "md5"); + return (pkalgo > 0 ? 0 : -1); +} + +int pgp_sign(BUFFER *msg, BUFFER *msg2, BUFFER *sig, BUFFER *userid, + BUFFER *pass, int type, int self, long now, int remail, + BUFFER *keypacket, char *secring) +/* msg: data to be signed (buffer is modified) + msg2: additional data to be signed for certain sig types + sig: signature is placed here + userid: select signing key + pass: pass phrase for signing key + type: PGP signature type + self: is this a self-signature? + now: time of signature creation + remail: is this an anonymous message? + keypacket: signature key + secring: key ring with signature key */ +{ + BUFFER *key, *id, *d, *sub, *enc; + int algo, err = -1; + int version = 3, hashalgo; + int type1; + + id = buf_new(); + d = buf_new(); + sub = buf_new(); + enc = buf_new(); + key = buf_new(); + + if (now == 0) { + now = time(NULL); + if (remail) + now -= rnd_number(4 * 24 * 60 * 60); + } + if (keypacket) { + buf_rewind(keypacket); + algo = pgp_getkey(PK_SIGN, PGP_ANY, NULL, NULL, NULL, keypacket, key, id, NULL, pass); + } else + algo = pgpdb_getkey(PK_SIGN, PGP_ANY, NULL, NULL, NULL, key, userid, NULL, id, secring, + pass); + if (algo <= -1) { + err = algo; + goto end; + } + if (algo == PGP_S_DSA || algo == PGP_E_ELG) + version = 4; + if (version == 3) + hashalgo = PGP_H_MD5; + else + hashalgo = PGP_H_SHA1; + + if (!self && type != PGP_SIG_BINDSUBKEY) + version = 3; + + switch (type) { + case PGP_SIG_CERT: + case PGP_SIG_CERT1: + case PGP_SIG_CERT2: + case PGP_SIG_CERT3: + type1 = pgp_getpacket(msg, d) == PGP_PUBKEY; + assert (type1); + buf_setc(msg, 0x99); + buf_appendi(msg, d->length); + buf_cat(msg, d); + + pgp_getpacket(msg2, d); + switch (version) { + case 3: + buf_cat(msg, d); + break; + case 4: + buf_appendc(msg, 0xb4); + buf_appendl(msg, d->length); + buf_cat(msg, d); + break; + } + break; + case PGP_SIG_BINDSUBKEY: + type1 = pgp_getpacket(msg, d) == PGP_PUBKEY; + assert (type1); + buf_clear(msg); + buf_appendc(msg, 0x99); + buf_appendi(msg, d->length); + buf_cat(msg, d); + + type1 = pgp_getpacket(msg2, d) == PGP_PUBSUBKEY; + assert (type1); + buf_appendc(msg, 0x99); + buf_appendi(msg, d->length); + buf_cat(msg, d); + break; + case PGP_SIG_BINARY: + break; + case PGP_SIG_CANONIC: + pgp_sigcanonic(msg); + break; + default: + NOT_IMPLEMENTED; + } + switch (version) { + case 3: + buf_set(d, msg); + buf_appendc(d, type); + buf_appendl(d, now); + pgp_digest(hashalgo, d, d); + if (algo == PGP_ES_RSA) + asnprefix(enc, hashalgo); + buf_cat(enc, d); + err = pgp_dosign(algo, enc, key); + + buf_setc(sig, version); + buf_appendc(sig, 5); + buf_appendc(sig, type); + buf_appendl(sig, now); + buf_cat(sig, id); + buf_appendc(sig, algo); + buf_appendc(sig, hashalgo); + buf_append(sig, d->data, 2); + buf_cat(sig, enc); + break; + + case 4: + buf_setc(sig, version); + buf_appendc(sig, type); + buf_appendc(sig, algo); + buf_appendc(sig, hashalgo); + + buf_clear(d); + buf_appendl(d, now); + pgp_subpacket(d, PGP_SUB_CREATIME); + buf_cat(sub, d); + + if (self || type == PGP_SIG_BINDSUBKEY) { + /* until we can handle the case where our pgp keys expire, don't create keys that expire */ + if (0 && KEYLIFETIME) { /* add key expirtaion time */ + buf_clear(d); + buf_appendl(d, KEYLIFETIME); + pgp_subpacket(d, PGP_SUB_KEYEXPIRETIME); + buf_cat(sub, d); + } + } + + if (self) { + buf_setc(d, PGP_K_CAST5); +#ifdef USE_AES + buf_appendc(d, PGP_K_AES128); +#endif /* USE_AES */ + buf_appendc(d, PGP_K_3DES); + pgp_subpacket(d, PGP_SUB_PSYMMETRIC); + buf_cat(sub, d); + + buf_setc(d, 0x01); /* now we support MDC, so we can add MDC flag */ + pgp_subpacket(d, PGP_SUB_FEATURES); + buf_cat(sub, d); + } + + buf_appendi(sig, sub->length); /* hashed subpacket length */ + buf_cat(sig, sub); + + /* compute message digest */ + buf_set(d, msg); + buf_cat(d, sig); + buf_appendc(d, version); + buf_appendc(d, 0xff); + buf_appendl(d, sig->length); + pgp_digest(hashalgo, d, d); + + pgp_subpacket(id, PGP_SUB_ISSUER); + buf_appendi(sig, id->length); /* unhashed subpacket length */ + buf_cat(sig, id); + + buf_append(sig, d->data, 2); + + if (algo == PGP_ES_RSA) + asnprefix(enc, hashalgo); + buf_cat(enc, d); + err = pgp_dosign(algo, enc, key); + buf_cat(sig, enc); + break; + } + pgp_packet(sig, PGP_SIG); + +end: + buf_free(key); + buf_free(id); + buf_free(d); + buf_free(sub); + buf_free(enc); + return (err); +} + +int pgp_pubkeycert(BUFFER *userid, char *keyring, BUFFER *pass, + BUFFER *out, int remail) +{ + BUFFER *key; + KEYRING *r; + int err = -1; + + key = buf_new(); + r = pgpdb_open(keyring, pass, 0, PGP_TYPE_UNDEFINED); + if (r != NULL) + while (pgpdb_getnext(r, key, NULL, userid) != -1) { + if (pgp_makepubkey(key, NULL, out, pass, 0) != -1) + err = 0; + } + if (err == 0) + pgp_armor(out, remail); + else + buf_clear(out); + buf_free(key); + return (err); +} + +#endif /* USE_PGP */ diff --git a/Src/pgpdata.c b/Src/pgpdata.c @@ -0,0 +1,1539 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + OpenPGP data + $Id: pgpdata.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#ifdef USE_PGP +#include "pgp.h" +#include "crypto.h" +#include <assert.h> +#include <time.h> +#include <string.h> + +int pgp_keylen(int symalgo) +{ + switch (symalgo) { +#ifdef USE_AES + case PGP_K_AES256: + return (32); + case PGP_K_AES192: + return (24); + case PGP_K_AES128: +#endif /* USE_AES */ + case PGP_K_IDEA: + case PGP_K_CAST5: + case PGP_K_BF: + return (16); + case PGP_K_3DES: + return (24); + default: + return (0); + } +} + +int pgp_blocklen(int symalgo) +{ + switch (symalgo) { +#ifdef USE_AES + case PGP_K_AES256: + case PGP_K_AES192: + case PGP_K_AES128: + return (16); +#endif /* USE_AES */ + case PGP_K_IDEA: + case PGP_K_CAST5: + case PGP_K_BF: + case PGP_K_3DES: + return (8); + default: + return (16); + } +} + +int mpi_get(BUFFER *b, BUFFER *mpi) +{ + int l; + + l = buf_geti(b); + buf_clear(mpi); + + if (l <= 0 || b->ptr + (l + 7) / 8 > b->length) + return (-1); + buf_get(b, mpi, (l + 7) / 8); + return (l); +} + + +int mpi_bitcount(BUFFER *mpi) +{ + int i, l; + while (!mpi->data[0] && mpi->length) /* remove leading zeros from mpi */ + memmove(mpi->data, mpi->data+1, --mpi->length); + l = mpi->length * 8; + for (i = 7; i >= 0; i--) + if (((mpi->data[0] >> i) & 1) == 1) { + l -= 7 - i; + break; + } + return l; +} + +int mpi_put(BUFFER *b, BUFFER *mpi) +{ + buf_appendi(b, mpi_bitcount(mpi)); + buf_cat(b, mpi); + return (0); +} + +int skcrypt(BUFFER *data, int skalgo, BUFFER *key, BUFFER *iv, int enc) +{ + switch (skalgo) { + case 0: + return (0); +#ifdef USE_IDEA + case PGP_K_IDEA: + return (buf_ideacrypt(data, key, iv, enc)); +#endif /* USE_IDEA */ +#ifdef USE_AES + case PGP_K_AES128: + case PGP_K_AES192: + case PGP_K_AES256: + return (buf_aescrypt(data, key, iv, enc)); +#endif /* USE_AES */ + case PGP_K_3DES: + return (buf_3descrypt(data, key, iv, enc)); + case PGP_K_BF: + return (buf_bfcrypt(data, key, iv, enc)); + case PGP_K_CAST5: + return (buf_castcrypt(data, key, iv, enc)); + default: + return (-1); + } +} + +int pgp_csum(BUFFER *key, int start) +{ + int i, csum = 0; + for (i = start; i < key->length; i++) + csum = (csum + key->data[i]) % 65536; + return (csum); +} + +int pgp_rsa(BUFFER *in, BUFFER *k, int mode) +{ + BUFFER *mpi, *out; + int err = -1; + RSA *key; + + assert(mode == PK_ENCRYPT || mode == PK_VERIFY || mode == PK_DECRYPT + || mode == PK_SIGN); + key = RSA_new(); + out = buf_new(); + mpi = buf_new(); + + mpi_get(k, mpi); + key->n = BN_bin2bn(mpi->data, mpi->length, NULL); + + if (mpi_get(k, mpi) < 0) + goto end; + key->e = BN_bin2bn(mpi->data, mpi->length, NULL); + + if (mode == PK_DECRYPT || mode == PK_SIGN) { + if (mpi_get(k, mpi) < 0) + goto end; + key->d = BN_bin2bn(mpi->data, mpi->length, NULL); + +#if 1 + /* compute auxiluary parameters */ + mpi_get(k, mpi); /* PGP'p is SSLeay's q */ + key->q = BN_bin2bn(mpi->data, mpi->length, NULL); + + mpi_get(k, mpi); + key->p = BN_bin2bn(mpi->data, mpi->length, NULL); + + if (mpi_get(k, mpi) < 0) + goto end; + key->iqmp = BN_bin2bn(mpi->data, mpi->length, NULL); + + { + BIGNUM *i; + BN_CTX *ctx; + + ctx = BN_CTX_new(); + i = BN_new(); + key->dmp1 = BN_new(); + key->dmq1 = BN_new(); + + BN_sub(i, key->p, BN_value_one()); + BN_mod(key->dmp1, key->d, i, ctx); + + BN_sub(i, key->q, BN_value_one()); + BN_mod(key->dmq1, key->d, i, ctx); + + BN_free(i); + } +#endif /* 1 */ + } + buf_prepare(out, RSA_size(key)); + + switch (mode) { + case PK_ENCRYPT: + out->length = RSA_public_encrypt(in->length, in->data, out->data, key, + RSA_PKCS1_PADDING); + break; + case PK_VERIFY: + out->length = RSA_public_decrypt(in->length, in->data, out->data, key, + RSA_PKCS1_PADDING); + break; + case PK_SIGN: + out->length = RSA_private_encrypt(in->length, in->data, out->data, key, + RSA_PKCS1_PADDING); + break; + case PK_DECRYPT: + out->length = RSA_private_decrypt(in->length, in->data, out->data, key, + RSA_PKCS1_PADDING); + break; + } + if (out->length == -1) + err = -1, out->length = 0; + else + err = 0; + + buf_move(in, out); +end: + RSA_free(key); + buf_free(out); + buf_free(mpi); + return (err); +} + +/* Contrary to RFC 2440, old PGP versions use this for clearsign only. + * If the text is included in the OpenPGP message, the application will + * typically provide the text in the proper format (whatever that is); + * we use "canonic" format so everybody will be able to read our messages. + * In clearsigned messages, trailing whitespace is always ignored. + * Detached signatures are the problematic case. For PGP/MIME, we always + * escape trailing whitespace as quoted-printable. + */ +void pgp_sigcanonic(BUFFER *msg) +{ + BUFFER *line, *out; + + out = buf_new(); + line = buf_new(); + + while (buf_getline(msg, line) != -1) { + while (line->length > 0 && (line->data[line->length - 1] == ' ' +#if 0 + || line->data[line->length - 1] == '\t' +#endif /* 0 */ + )) + line->length--; + line->data[line->length] = '\0'; + buf_cat(out, line); + buf_appends(out, "\r\n"); + } + buf_move(msg, out); + buf_free(out); + buf_free(line); +} + +static void mpi_bnput(BUFFER *o, BIGNUM *i) +{ + BUFFER *b; + + b = buf_new(); + buf_prepare(b, BN_num_bytes(i)); + b->length = BN_bn2bin(i, b->data); + mpi_put(o, b); + buf_free(b); +} + +static void mpi_bnputenc(BUFFER *o, BIGNUM *i, int ska, BUFFER *key, + BUFFER *iv) +{ + BUFFER *b; + int ivlen = iv->length; + + b = buf_new(); + buf_prepare(b, BN_num_bytes(i)); + b->length = BN_bn2bin(i, b->data); + buf_appendi(o, mpi_bitcount(b)); + if (key && key->length) { + skcrypt(b, ska, key, iv, ENCRYPT); + buf_clear(iv); + buf_append(iv, b->data+b->length-ivlen, ivlen); + } + buf_cat(o, b); + buf_free(b); +} + +static int getski(BUFFER *p, BUFFER *pass, BUFFER *key, BUFFER *iv) +{ + int skalgo; + BUFFER *salt, *temp; + + if (!pass) + return(-1); + + salt = buf_new(); + temp = buf_new(); + + skalgo = buf_getc(p); + switch (skalgo) { + case 0: + /* none */ + goto end; + case 255: + /* S2K specifier */ + skalgo = pgp_getsk(p, pass, key); + break; + default: + /* simple */ + digest_md5(pass, key); + break; + } + + buf_get(p, iv, pgp_blocklen(skalgo)); + + end: + buf_free(salt); + buf_free(temp); + return (skalgo); +} + +static void makeski(BUFFER *secret, BUFFER *pass, int remail) +{ + BUFFER *out, *key, *iv; + out = buf_new(); + key = buf_new(); + iv = buf_new(); + if (pass == NULL || pass->length == 0 || remail == 2) { + buf_appendc(out, 0); + buf_cat(out, secret); + } else { + buf_appendc(out, 255); + pgp_makesk(out, key, PGP_K_CAST5, 3, PGP_H_SHA1, pass); + buf_setrnd(iv, pgp_blocklen(PGP_K_CAST5)); + buf_cat(out, iv); + skcrypt(secret, PGP_K_CAST5, key, iv, 1); + buf_cat(out, secret); + } + buf_move(secret, out); + buf_free(out); + buf_free(key); + buf_free(iv); +} + +int pgp_nummpi(int algo) +{ + switch (algo) { + case PGP_ES_RSA: + return (2); + case PGP_S_DSA: + return (4); + case PGP_E_ELG: + return (3); + default: + return (0); + } +} + +int pgp_numsecmpi(int algo) +{ + switch (algo) { + case PGP_ES_RSA: + return (4); + case PGP_S_DSA: + return (1); + case PGP_E_ELG: + return (1); + default: + return (0); + } +} + +/* store key's ID in keyid */ +int pgp_keyid(BUFFER *key, BUFFER *keyid) +{ + BUFFER *i, *k; + int version, algo, j, ptr; + + i = buf_new(); + k = buf_new(); + + ptr = key->ptr; + key->ptr = 0; + switch (version = buf_getc(key)) { + case 2: + case 3: + buf_getl(key); + buf_geti(key); + buf_getc(key); + mpi_get(key, i); + break; + case 4: + buf_appendc(k, version); + buf_appendl(k, buf_getl(key)); + algo = buf_getc(key); + buf_appendc(k, algo); + if (pgp_nummpi(algo) == 0) + buf_rest(k, key); /* works for public keys only */ + else + for (j = 0; j < pgp_nummpi(algo); j++) { + mpi_get(key, i); + mpi_put(k, i); + } + buf_clear(i); + buf_appendc(i, 0x99); + buf_appendi(i, k->length); + buf_cat(i, k); + digest_sha1(i, i); + break; + } + buf_clear(keyid); + buf_append(keyid, i->data + i->length - 8, 8); + buf_free(i); + buf_free(k); + key->ptr = ptr; + return(0); +} + +static int pgp_iskeyid(BUFFER *key, BUFFER *keyid) +{ + BUFFER *thisid; + int ret; + + thisid = buf_new(); + pgp_keyid(key, thisid); + ret = buf_eq(keyid, thisid); + buf_free(thisid); + return(ret); +} + +static int pgp_get_sig_subpacket(BUFFER * p1, BUFFER *out) +{ + int suptype, len = buf_getc(p1); + if (len > 192 && len < 255) + len = (len - 192) * 256 + buf_getc(p1) + 192; + else if (len == 255) + len = buf_getl(p1); + suptype = buf_getc(p1); + if (len) + buf_get(p1, out, len-1); /* len-1 - exclude type */ + else + buf_clear(out); + return suptype; +} + +typedef struct _UIDD { + struct _UIDD * next; + long created, expires; + int revoked, sym, mdc, uid, primary; + BUFFER *uidstr; +} UIDD; + +static UIDD * new_uidd_c(UIDD *uidd_c, int uidno) +{ + UIDD * tmp; + + if (!uidd_c || uidd_c->uid < uidno) { + tmp = (UIDD *)malloc(sizeof(UIDD)); + if (!tmp) + return uidd_c; + if (uidd_c) { + uidd_c->next = tmp; + uidd_c = uidd_c->next; + } else + uidd_c = tmp; + if (uidd_c) { + memset(uidd_c, 0, sizeof(UIDD)); + uidd_c->uid = uidno; + } + } + return uidd_c; +} + +int pgp_getkey(int mode, int algo, int *psym, int *pmdc, long *pexpires, BUFFER *keypacket, BUFFER *key, + BUFFER *keyid, BUFFER *userid, BUFFER *pass) +/* IN: mode - PK_SIGN, PK_VERIFY, PK_DECRYPT, PK_ENCRYPT + * algo - PGP_ANY, PGP_ES_RSA, PGP_E_ELG, PGP_S_DSA + * psym - reyested sym PGP_K_ANY, PGP_K_IDEA, PGP_K_3DES, ... or NULL + * pass - passprase or NULL + * keypacket - key, with key uid sig subkey packets, possibly encrypted + * keyid - reyested (sub)keyid or empty buffer or NULL + * OUT: psym - found sym algo (or NULL) + * pmdc - found mdc flag (or NULL) + * key - found key, only key packet, decrypted + * may be the same buffer as keypacket (or NULL) + * keyid - found (sub)keyid (or NULL) + * userid - found userid (or NULL) + * pexpires - expiry time, or 0 if don't expire (or NULL) + */ +{ + int tempbuf = 0, dummykey = 0; + int keytype = -1, type, j; + int thisalgo = 0, version, skalgo; + int needsym = 0, symfound = 0, mdcfound = 0; + BUFFER *p1, *iv, *sk, *i, *thiskeyid, *mainkeyid; + int ivlen; + int csstart; + long now = time(NULL); + long created = 0, expires = 0, subexpires = 0; + int uidno = 0, primary = 0, subkeyno = 0, subkeyok = 0; + UIDD * uidd_1 = NULL, * uidd_c = NULL; + + p1 = buf_new(); + i = buf_new(); + iv = buf_new(); + sk = buf_new(); + thiskeyid = buf_new(); + mainkeyid = buf_new(); + if (psym) + needsym = *psym; + if (keypacket == key) { + key = buf_new(); + tempbuf = 1; + } + if (! key) { + key = buf_new(); + dummykey = 1; + }; + if (userid) + buf_clear(userid); + + while ((type = pgp_getpacket(keypacket, p1)) > 0) { + switch (type) { + case PGP_SIG: + { + /* it is assumed that only valid keys have been imported */ + long a; + int self = 0, certexpires = 0, suptype; + int sigtype = 0, sigver = buf_getc(p1); + created = 0, expires = 0, primary = 0; + if (sigver == 4) { + sigtype = buf_getc(p1); + if (isPGP_SIG_CERT(sigtype) || sigtype == PGP_SIG_BINDSUBKEY || sigtype == PGP_SIG_CERTREVOKE) { + int revoked = (sigtype == PGP_SIG_CERTREVOKE), sym = PGP_K_3DES, mdc = 0; + buf_getc(p1); /* pk algo */ + buf_getc(p1); /* hash algo */ + j = buf_geti(p1); /* length of hashed signature subpackets */ + j += p1->ptr; + while (p1->ptr < j) { + suptype = pgp_get_sig_subpacket(p1, i); + switch (suptype & 0x7F) { + case PGP_SUB_PSYMMETRIC: + while ((a = buf_getc(i)) != -1) + if ((a == PGP_K_3DES || a == PGP_K_CAST5 || a == PGP_K_BF +#ifdef USE_IDEA + || a == PGP_K_IDEA +#endif /* USE_IDEA */ +#ifdef USE_AES + || a == PGP_K_AES128 || a == PGP_K_AES192 || a == PGP_K_AES256 +#endif /* USE_AES */ + ) && (a == needsym || needsym == PGP_K_ANY)) { + sym = a; + break; /* while ((a = buf_getc(i)) != -1) */ + } /* if ((a == PGP_K_3DES)... */ + break; + case PGP_SUB_FEATURES: + if ((a = buf_getc(i)) != -1) + if (a & 0x01) + mdc = 1; + break; + case PGP_SUB_CREATIME: + if ((a = buf_getl(i)) != -1) + created = a; + break; + case PGP_SUB_KEYEXPIRETIME: + if ((a = buf_getl(i)) != -1) + expires = a; + break; + case PGP_SUB_CERTEXPIRETIME: + if ((a = buf_getl(i)) != -1) + certexpires = a; + break; + case PGP_SUB_ISSUER: /* ISSUER normaly is in unhashed data, but check anyway */ + if (i->length == 8) + self = buf_eq(i, mainkeyid); + break; + case PGP_SUB_PRIMARY: + if ((a = buf_getl(i)) != -1) + primary = a; + break; + default: + if (suptype & 0x80) { + ; /* "critical" bit set! now what? */ + } + } /* switch (suptype) */ + } /* while (p1->ptr < j) */ + if (p1->ptr == j) { + j = buf_geti(p1); /* length of unhashed signature subpackets */ + j += p1->ptr; + while (p1->ptr < j) { + suptype = pgp_get_sig_subpacket(p1, i); + if (suptype == PGP_SUB_ISSUER) { + if (i->length == 8) + self = buf_eq(i, mainkeyid); + } /* if (suptype == PGP_SUB_ISSUER) */ + } /* while (p1->ptr < j) #2 */ + } /* if (p1->ptr == j) */ + if (p1->ptr != j) /* sig damaged ? */ + break; /* switch (type) */ + if (self) { + if (certexpires) + certexpires = ((created + certexpires < now) || (created + certexpires < 0)); + if ((isPGP_SIG_CERT(sigtype) && !certexpires) || sigtype == PGP_SIG_CERTREVOKE) { + uidd_c = new_uidd_c(uidd_c, uidno); + if (!uidd_1) + uidd_1 = uidd_c; + if (uidd_c && uidd_c->uid == uidno) { + if (uidd_c->created <= created) { + /* if there is several selfsigs on that uid, find the newest one */ + uidd_c->created = created; + uidd_c->expires = expires; + uidd_c->revoked = revoked; + uidd_c->primary = primary; + uidd_c->sym = sym; + uidd_c->mdc = mdc; + } + } + } /* if ((isPGP_SIG_CERT(sigtype) && !certexpires) || sigtype == PGP_SIG_CERTREVOKE) */ + else if (sigtype == PGP_SIG_BINDSUBKEY) { + if (!subkeyok) { + subexpires = expires ? created + expires : 0; + if (expires && ((created + expires < now) || (created + expires < 0))) { + if (mode == PK_ENCRYPT) { /* allow decrypt with expired subkeys, but not encrypt */ + keytype = -1; + } + } + if (keytype != -1) + subkeyok = subkeyno; + } + } /* if (sigtype == PGP_SIG_BINDSUBKEY) */ + } /* if (self) */ + } /* if (isPGP_SIG_CERT(sigtype) || sigtype == PGP_SIG_BINDSUBKEY || sigtype == PGP_SIG_CERTREVOKE) */ + } /* if (sigver == 4) */ + else if (sigver == 2 || sigver == 3) { + buf_getc(p1); /* One-octet length of following hashed material. MUST be 5 */ + sigtype = buf_getc(p1); + } /* if (sigver == 2 || sigver == 3) */ + if (sigtype == PGP_SIG_KEYREVOKE) { + /* revocation can be either v3 or v4. if v4 we could check issuer, but we don't do it... */ + if (mode == PK_SIGN || mode == PK_ENCRYPT) { /* allow verify and decrypt with revokeded keys, but not sign and encrypt */ + keytype = -1; + } + } /* if (sigtype == PGP_SIG_KEYREVOKE) */ + else if (sigtype == PGP_SIG_SUBKEYREVOKE) { + if (!subkeyok || subkeyok == subkeyno) + if (mode == PK_ENCRYPT) { /* allow decrypt with revokeded subkeys, but not encrypt */ + keytype = -1; + } + } /* if (sigtype == PGP_SIG_SUBKEYREVOKE) */ + break; /* switch (type) */ + } /* case PGP_SIG: */ + case PGP_USERID: + uidno++; + uidd_c = new_uidd_c(uidd_c, uidno); + if (!uidd_1) + uidd_1 = uidd_c; + if (uidd_c && uidd_c->uid == uidno) { + uidd_c->uidstr = buf_new(); + buf_set(uidd_c->uidstr, p1); + } + if (userid) + buf_move(userid, p1); + break; + case PGP_PUBSUBKEY: + case PGP_SECSUBKEY: + subkeyno++; + if (keytype != -1 && subkeyno > 1) { + /* usable subkey already found, don't bother to check other */ + continue; + } + if (keytype != -1 && (mode == PK_SIGN || mode == PK_VERIFY)) + continue; + case PGP_PUBKEY: + if ((type == PGP_PUBKEY || type == PGP_PUBSUBKEY) && + (mode == PK_DECRYPT || mode == PK_SIGN)) + continue; + case PGP_SECKEY: + if (type == PGP_PUBKEY || type == PGP_SECKEY) + pgp_keyid(p1, mainkeyid); + keytype = type; + version = buf_getc(p1); + switch (version) { + case 2: + case 3: + created = buf_getl(p1); /* created */ + expires = buf_geti(p1) * (24*60*60); /* valid */ + if (uidno == 0) { + uidd_c = new_uidd_c(uidd_c, uidno); + if (!uidd_1) + uidd_1 = uidd_c; + if (uidd_c && uidd_c->uid == uidno) { + uidd_c->created = created; + uidd_c->expires = expires; + uidd_c->sym = PGP_K_IDEA; + } + } + thisalgo = buf_getc(p1); + if (thisalgo != PGP_ES_RSA) { + keytype = -1; + goto end; + } + symfound = PGP_K_IDEA; + mdcfound = 0; + break; + case 4: + buf_appendc(key, version); + buf_appendl(key, buf_getl(p1)); + thisalgo = buf_getc(p1); + buf_appendc(key, thisalgo); + if (symfound == 0) + symfound = PGP_K_3DES; /* default algorithm */ + break; + default: + keytype = -1; + goto end; + } /* switch (version) */ + if (algo != PGP_ANY && thisalgo != algo) { + keytype = -1; + continue; + } + if (keyid && keyid->length && !pgp_iskeyid(p1, keyid)) + continue; + pgp_keyid(p1, thiskeyid); + if (key) { + buf_clear(key); + for (j = 0; j < pgp_nummpi(thisalgo); j++) { + if (mpi_get(p1, i) == -1) + goto end; + mpi_put(key, i); + } + if (keytype == PGP_SECKEY || keytype == PGP_SECSUBKEY) { + csstart = key->length; + skalgo = getski(p1, pass, sk, iv); + switch (version) { + case 2: + case 3: + ivlen = pgp_blocklen(skalgo); + for (j = 0; j < pgp_numsecmpi(thisalgo); j++) { + unsigned char lastb[16]; + if (mpi_get(p1, i) == -1) { + keytype = -1; + goto end; + } + assert(ivlen <= 16); + memcpy(lastb, i->data+i->length-ivlen, ivlen); + skcrypt(i, skalgo, sk, iv, DECRYPT); + buf_clear(iv); + buf_append(iv, lastb, ivlen); + mpi_put(key, i); + } /* for */ + break; /* switch (version) */ + case 4: + buf_clear(i); + buf_rest(i, p1); + skcrypt(i, skalgo, sk, iv, DECRYPT); + buf_move(p1, i); + for (j = 0; j < pgp_numsecmpi(thisalgo); j++) { + if (mpi_get(p1, i) == -1) { + keytype = PGP_PASS; + goto end; + } + mpi_put(key, i); + } + break; + } /* switch (version) */ + if (pgp_csum(key, csstart) != buf_geti(p1)) { + keytype = PGP_PASS; + goto end; + } + } + } /* if (key) */ + break; /* switch (type) */ + default: + /* ignore trust packets etc */ + break; + } /* switch (type) */ + } /* while ((type = pgp_getpacket(keypacket, p1)) > 0) */ + end: + if (keyid) buf_set(keyid, thiskeyid); + if (tempbuf) { + buf_move(keypacket, key); + buf_free(key); + } + if (dummykey) { + buf_free(key); + } + buf_free(p1); + buf_free(i); + buf_free(iv); + buf_free(sk); + buf_free(thiskeyid); + buf_free(mainkeyid); + + if (uidd_1) { + primary = 0; + created = expires = 0; + while (uidd_1) { + /* find newest uid which is not revoked or expired */ + if (primary <= uidd_1->primary && created <= uidd_1->created && !uidd_1->revoked) { + created = uidd_1->created; + expires = uidd_1->expires; + primary = uidd_1->primary; + symfound = uidd_1->sym; + mdcfound = uidd_1->mdc; + if (userid && uidd_1->uidstr) + buf_set(userid, uidd_1->uidstr); + } + uidd_c = uidd_1; + uidd_1 = uidd_1->next; + if (uidd_c->uidstr) + buf_free(uidd_c->uidstr); + free(uidd_c); + } + if (expires && ((created + expires < now) || (created + expires < 0))) { + if (mode == PK_SIGN || mode == PK_ENCRYPT) { /* allow verify and decrypt with expired keys, but not sign and encrypt */ + keytype = -1; + } + } + } /* if (uidd_1) */ + expires = expires ? created + expires : 0; + if (subexpires > 0 && expires > 0 && subexpires < expires) + expires = subexpires; + if (pexpires) + *pexpires = expires; + + if (!subkeyok && keytype == PGP_E_ELG && (mode == PK_DECRYPT || mode == PK_ENCRYPT)) + keytype = -1; /* no usable subkey found, one with valid binding */ + + if (needsym != PGP_K_ANY && needsym != symfound) + keytype = -1; + else if (psym && *psym == PGP_K_ANY) + *psym = symfound; + if (pmdc) + *pmdc = mdcfound; + + return (keytype <= 0 ? keytype : thisalgo); +} + +int pgp_makepkpacket(int type, BUFFER *p, BUFFER *outtxt, BUFFER *out, + BUFFER *key, BUFFER *pass, time_t *created) +{ + BUFFER *i, *id; + char txt[LINELEN], algoid; + int version, algo, valid = 0, err = 0; + int len, j; + struct tm *tc; + + i = buf_new(); + id = buf_new(); + + version = buf_getc(p); + buf_clear(key); + switch (version) { + case 2: + case 3: + *created = buf_getl(p); + valid = buf_geti(p); + algo = buf_getc(p); + if (algo != PGP_ES_RSA) + return(-1); + break; + case 4: + *created = buf_getl(p); + algo = buf_getc(p); + break; + default: + return(-1); + } + + switch (version) { + case 2: + case 3: + buf_appendc(key, version); + buf_appendl(key, *created); + buf_appendi(key, valid); + buf_appendc(key, algo); + break; + case 4: + buf_appendc(key, version); + buf_appendl(key, *created); + buf_appendc(key, algo); + break; + } + + pgp_keyid(p, id); + len = mpi_get(p, i); + mpi_put(key, i); + for (j = 1; j < pgp_nummpi(algo); j++) { + if (mpi_get(p, i) == -1) { + err = -1; + goto end; + } + mpi_put(key, i); + } + pgp_packet(key, type); + buf_cat(out, key); + + if (outtxt != NULL) { + switch(algo) { + case PGP_ES_RSA: + algoid = 'R'; + break; + case PGP_S_DSA: + algoid = 'D'; + break; + case PGP_E_ELG: + algoid = 'g'; + break; + default: + algoid = '?'; + } + buf_appendf(outtxt, "%s %5d%c/%02X%02X%02X%02X ", + type == PGP_PUBSUBKEY ? "sub" : + type == PGP_PUBKEY ? "pub" : + type == PGP_SECKEY ? "sec" : + type == PGP_SECSUBKEY ? "ssb" : + "???", len, algoid, + id->data[4], id->data[5], id->data[6], id->data[7]); + tc = localtime(created); + strftime(txt, LINELEN, "%Y-%m-%d ", tc); + buf_appends(outtxt, txt); + } + end: + buf_free(i); + buf_free(id); + return(err == 0 ? algo : err); +} + +int pgp_makepubkey(BUFFER *keypacket, BUFFER *outtxt, BUFFER *out, + BUFFER *pass, int keyalgo) +{ + BUFFER *p, *pubkey, *seckey, *subkey, *sig, *tmp; + int err = -1, type, thisalgo; + time_t created; + + p = buf_new(); + seckey = buf_new(); + pubkey = buf_new(); + subkey = buf_new(); + sig = buf_new(); + tmp = buf_new(); + + buf_set(seckey, keypacket); + type = pgp_getpacket(keypacket, p); + if (type != PGP_SECKEY) + goto end; + + thisalgo = pgp_makepkpacket(PGP_PUBKEY, p, outtxt, tmp, pubkey, pass, + &created); + if (thisalgo == -1 || (keyalgo != 0 && keyalgo != thisalgo)) + goto end; + buf_cat(out, tmp); + + while ((type = pgp_getpacket(keypacket, p)) > 0) { + if (type == PGP_SECSUBKEY) { + if (pgp_makepkpacket(PGP_PUBSUBKEY, p, outtxt, out, subkey, pass, + &created) == -1) + goto end; + if (pgp_sign(pubkey, subkey, sig, NULL, pass, PGP_SIG_BINDSUBKEY, 0, + created, 0, seckey, NULL) != -1) + buf_cat(out, sig); + if (outtxt) + buf_nl(outtxt); + } else if (type == PGP_USERID) { + if (outtxt != NULL) { + buf_cat(outtxt, p); + buf_nl(outtxt); + } + pgp_packet(p, PGP_USERID); + err = pgp_sign(pubkey, p, sig, NULL, pass, PGP_SIG_CERT, 1, created, 0, + seckey, NULL); /* maybe PGP_SIG_CERT3 ? */ + buf_cat(out, p); + if (err == 0) + buf_cat(out, sig); + } else if (type == PGP_PUBKEY || type == PGP_SECKEY) + break; + } +end: + buf_free(pubkey); + buf_free(seckey); + buf_free(subkey); + buf_free(sig); + buf_free(p); + buf_free(tmp); + return (err); +} + +int pgp_makekeyheader(int type, BUFFER *keypacket, BUFFER *outtxt, + BUFFER *pass, int keyalgo) +{ + BUFFER *p, *pubkey, *seckey, *subkey, *sig, *tmp, *dummy; + int thisalgo, err = -1; + time_t created; + + assert(type == PGP_SECKEY || type == PGP_PUBKEY); + + p = buf_new(); + seckey = buf_new(); + pubkey = buf_new(); + subkey = buf_new(); + sig = buf_new(); + tmp = buf_new(); + dummy = buf_new(); + + buf_set(seckey, keypacket); + if (type != pgp_getpacket(keypacket, p)) + goto end; + + thisalgo = pgp_makepkpacket(type, p, outtxt, tmp, pubkey, pass, + &created); + if (thisalgo == -1 || (keyalgo != 0 && keyalgo != thisalgo)) + goto end; + + while ((type = pgp_getpacket(keypacket, p)) > 0) { + if (type == PGP_SECSUBKEY || type == PGP_PUBSUBKEY) { + if (pgp_makepkpacket(type, p, outtxt, dummy, subkey, pass, + &created) == -1) + goto end; + buf_nl(outtxt); + } else if (type == PGP_USERID) { + buf_cat(outtxt, p); + buf_nl(outtxt); + pgp_packet(p, PGP_USERID); + } else if (type == PGP_PUBKEY || type == PGP_SECKEY) + break; + } + err = 0; +end: + buf_free(pubkey); + buf_free(seckey); + buf_free(subkey); + buf_free(sig); + buf_free(p); + buf_free(dummy); + buf_free(tmp); + return (err); +} + +int pgp_rsakeygen(int bits, BUFFER *userid, BUFFER *pass, char *pubring, + char *secring, int remail) + /* remail==2: encrypt the secring */ +{ + RSA *k; + KEYRING *keydb; + BUFFER *pkey, *skey; + BUFFER *dk, *sig, *iv, *p; + long now; + int skalgo = 0; + int err = 0; + + pkey = buf_new(); + skey = buf_new(); + iv = buf_new(); + dk = buf_new(); + p = buf_new(); + sig = buf_new(); + + errlog(NOTICE, "Generating OpenPGP RSA key.\n"); + k = RSA_generate_key(bits == 0 ? 1024 : bits, 17, NULL, NULL); + if (k == NULL) { + err = -1; + goto end; + } + now = time(NULL); + if (remail) /* fake time in nym keys */ + now -= rnd_number(4 * 24 * 60 * 60); + + buf_appendc(skey, 3); + buf_appendl(skey, now); + /* until we can handle the case, where our key expires, don't create keys with expiration dates */ + buf_appendi(skey, 0); + /* buf_appendi(skey, KEYLIFETIME/(24*60*60)); */ + buf_appendc(skey, PGP_ES_RSA); + mpi_bnput(skey, k->n); + mpi_bnput(skey, k->e); + +#ifdef USE_IDEA + if (pass != NULL && pass->length > 0 && remail != 2) { + skalgo = PGP_K_IDEA; + digest_md5(pass, dk); + buf_setrnd(iv, pgp_blocklen(skalgo)); + buf_appendc(skey, skalgo); + buf_cat(skey, iv); + } + else +#endif /* USE_IDEA */ + buf_appendc(skey, 0); + + mpi_bnputenc(skey, k->d, skalgo, dk, iv); + mpi_bnputenc(skey, k->q, skalgo, dk, iv); + mpi_bnputenc(skey, k->p, skalgo, dk, iv); + mpi_bnputenc(skey, k->iqmp, skalgo, dk, iv); + + buf_clear(p); + mpi_bnput(p, k->d); + mpi_bnput(p, k->q); + mpi_bnput(p, k->p); + mpi_bnput(p, k->iqmp); + buf_appendi(skey, pgp_csum(p, 0)); + + pgp_packet(skey, PGP_SECKEY); + buf_set(p, userid); + pgp_packet(p, PGP_USERID); + buf_cat(skey, p); + + if (secring == NULL) + secring = PGPREMSECRING; + keydb = pgpdb_open(secring, remail == 2 ? pass : NULL, 1, PGP_TYPE_PRIVATE); + if (keydb == NULL) { + err = -1; + goto end; + } + if (keydb->filetype == -1) + keydb->filetype = ARMORED; + pgpdb_append(keydb, skey); + pgpdb_close(keydb); + + if (pubring != NULL) { + if (pgp_makepubkey(skey, NULL, pkey, pass, 0) == -1) + goto end; + keydb = pgpdb_open(pubring, NULL, 1, PGP_TYPE_PUBLIC); + if (keydb == NULL) + goto end; + if (keydb->filetype == -1) + keydb->filetype = ARMORED; + pgpdb_append(keydb, pkey); + pgpdb_close(keydb); + } +end: + RSA_free(k); + buf_free(pkey); + buf_free(skey); + buf_free(iv); + buf_free(dk); + buf_free(p); + buf_free(sig); + return (err); +} + +#define begin_param "-----BEGIN PUBLIC PARAMETER BLOCK-----" +#define end_param "-----END PUBLIC PARAMETER BLOCK-----" + +static void *params(int dsa, int bits) +{ + DSA *k = NULL; + DH *d = NULL; + FILE *f; + BUFFER *p, *n; + char line[LINELEN]; + byte b[1024]; + int m, l; + + if (bits == 0) + bits = 1024; + if (dsa && bits > 1024) + bits = 1024; + + p = buf_new(); + n = buf_new(); + f = mix_openfile(dsa ? DSAPARAMS : DHPARAMS, "r"); + if (f != NULL) { + for (;;) { + if (fgets(line, sizeof(line), f) == NULL) + break; + if (strleft(line, begin_param)) { + if (fgets(line, sizeof(line), f) == NULL) + break; + m = 0; + sscanf(line, "%d", &m); + if (bits == m) { + buf_clear(p); + while (fgets(line, sizeof(line), f) != NULL) { + if (strleft(line, end_param)) { + decode(p, p); + if (dsa) { + k = DSA_new(); + l = buf_geti(p); + buf_get(p, n, l); + k->p = BN_bin2bn(n->data, n->length, NULL); + l = buf_geti(p); + buf_get(p, n, l); + k->q = BN_bin2bn(n->data, n->length, NULL); + l = buf_geti(p); + buf_get(p, n, l); + k->g = BN_bin2bn(n->data, n->length, NULL); + } else { + d = DH_new(); + l = buf_geti(p); + buf_get(p, n, l); + d->p = BN_bin2bn(n->data, n->length, NULL); + l = buf_geti(p); + buf_get(p, n, l); + d->g = BN_bin2bn(n->data, n->length, NULL); + } + break; + } + buf_appends(p, line); + } + } + } + } + fclose(f); + } + + buf_free(p); + buf_free(n); + + if (dsa) { + if (k == NULL) { + errlog(NOTICE, "Generating DSA parameters.\n"); + k = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); + p = buf_new(); + l = BN_bn2bin(k->p, b); + buf_appendi(p, l); + buf_append(p, b, l); + l = BN_bn2bin(k->q, b); + buf_appendi(p, l); + buf_append(p, b, l); + l = BN_bn2bin(k->g, b); + buf_appendi(p, l); + buf_append(p, b, l); + encode(p, 64); + f = mix_openfile(DSAPARAMS, "a"); + if (f != NULL) { + fprintf(f, "%s\n%d\n", begin_param, bits); + buf_write(p, f); + fprintf(f, "%s\n", end_param); + fclose(f); + } else + errlog(ERRORMSG, "Cannot open %s!\n", DSAPARAMS); + buf_free(p); + } + return (k); + } else { + if (d == NULL) { + errlog(NOTICE, "Generating DH parameters. (This may take a long time!)\n"); + d = DH_generate_parameters(bits, DH_GENERATOR_5, NULL, NULL); + p = buf_new(); + l = BN_bn2bin(d->p, b); + buf_appendi(p, l); + buf_append(p, b, l); + l = BN_bn2bin(d->g, b); + buf_appendi(p, l); + buf_append(p, b, l); + encode(p, 64); + f = mix_openfile(DHPARAMS, "a"); + if (f != NULL) { + fprintf(f, "%s\n%d\n", begin_param, bits); + buf_write(p, f); + fprintf(f, "%s\n", end_param); + fclose(f); + } else + errlog(ERRORMSG, "Cannot open %s!\n", DHPARAMS); + buf_free(p); + } + return (d); + } +} + +int pgp_dhkeygen(int bits, BUFFER *userid, BUFFER *pass, char *pubring, + char *secring, int remail) + /* remail==2: encrypt the secring */ +{ + DSA *s; + DH *e; + KEYRING *keydb; + BUFFER *pkey, *skey, *subkey, *secret; + BUFFER *dk, *sig, *iv, *p; + long now; + int err = 0; + + pkey = buf_new(); + skey = buf_new(); + subkey = buf_new(); + iv = buf_new(); + dk = buf_new(); + p = buf_new(); + sig = buf_new(); + secret = buf_new(); + + s = params(1, bits); + errlog(NOTICE, "Generating OpenPGP DSA key.\n"); + if (s == NULL || DSA_generate_key(s) != 1) { + err = -1; + goto end; + } + e = params(0, bits); + errlog(NOTICE, "Generating OpenPGP ElGamal key.\n"); + if (e == NULL || DH_generate_key(e) != 1) { + err = -1; + goto end; + } + + now = time(NULL); + if (remail) /* fake time in nym keys */ + now -= rnd_number(4 * 24 * 60 * 60); + + /* DSA key */ + buf_setc(skey, 4); + buf_appendl(skey, now); + buf_appendc(skey, PGP_S_DSA); + mpi_bnput(skey, s->p); + mpi_bnput(skey, s->q); + mpi_bnput(skey, s->g); + mpi_bnput(skey, s->pub_key); + + mpi_bnput(secret, s->priv_key); + buf_appendi(secret, pgp_csum(secret, 0)); + makeski(secret, pass, remail); + buf_cat(skey, secret); + pgp_packet(skey, PGP_SECKEY); + + /* ElGamal key */ + buf_setc(subkey, 4); + buf_appendl(subkey, now); + buf_appendc(subkey, PGP_E_ELG); + mpi_bnput(subkey, e->p); + mpi_bnput(subkey, e->g); + mpi_bnput(subkey, e->pub_key); + + buf_clear(secret); + mpi_bnput(secret, e->priv_key); + buf_appendi(secret, pgp_csum(secret, 0)); + makeski(secret, pass, remail); + buf_cat(subkey, secret); + + buf_set(p, userid); + pgp_packet(p, PGP_USERID); + buf_cat(skey, p); + + pgp_packet(subkey, PGP_SECSUBKEY); + buf_cat(skey, subkey); + + if (secring == NULL) + secring = PGPREMSECRING; + keydb = pgpdb_open(secring, remail == 2 ? pass : NULL, 1, PGP_TYPE_PRIVATE); + if (keydb == NULL) { + err = -1; + goto end; + } + if (keydb->filetype == -1) + keydb->filetype = ARMORED; + pgpdb_append(keydb, skey); + pgpdb_close(keydb); + + if (pubring != NULL) { + pgp_makepubkey(skey, NULL, pkey, pass, 0); + keydb = pgpdb_open(pubring, NULL, 1, PGP_TYPE_PUBLIC); + if (keydb == NULL) + goto end; + if (keydb->filetype == -1) + keydb->filetype = ARMORED; + pgpdb_append(keydb, pkey); + pgpdb_close(keydb); + } +end: + buf_free(pkey); + buf_free(skey); + buf_free(subkey); + buf_free(iv); + buf_free(dk); + buf_free(p); + buf_free(sig); + buf_free(secret); + return (err); +} + +int pgp_dsasign(BUFFER *data, BUFFER *key, BUFFER *out) +{ + BUFFER *mpi, *b; + DSA *d; + DSA_SIG *sig = NULL; + + d = DSA_new(); + b = buf_new(); + mpi = buf_new(); + mpi_get(key, mpi); + d->p = BN_bin2bn(mpi->data, mpi->length, NULL); + mpi_get(key, mpi); + d->q = BN_bin2bn(mpi->data, mpi->length, NULL); + mpi_get(key, mpi); + d->g = BN_bin2bn(mpi->data, mpi->length, NULL); + mpi_get(key, mpi); + d->pub_key = BN_bin2bn(mpi->data, mpi->length, NULL); + if (mpi_get(key, mpi) == -1) { + goto end; + } + d->priv_key = BN_bin2bn(mpi->data, mpi->length, NULL); + + sig = DSA_do_sign(data->data, data->length, d); + if (sig) { + buf_prepare(b, BN_num_bytes(sig->r)); + b->length = BN_bn2bin(sig->r, b->data); + mpi_put(out, b); + b->length = BN_bn2bin(sig->s, b->data); + mpi_put(out, b); + } + end: + buf_free(mpi); + buf_free(b); + DSA_SIG_free(sig); + DSA_free(d); + return(sig ? 0 : -1); +} + +int pgp_dosign(int algo, BUFFER *data, BUFFER *key) +{ + int err; + BUFFER *out, *r, *s; + + out = buf_new(); + r = buf_new(); + s = buf_new(); + switch (algo) { + case PGP_ES_RSA: + err = pgp_rsa(data, key, PK_SIGN); + if (err == 0) + mpi_put(out, data); + break; + case PGP_S_DSA: + err = pgp_dsasign(data, key, out); + break; + default: + errlog(NOTICE, "Unknown encryption algorithm!\n"); + return (-1); + } + if (err == -1) + errlog(ERRORMSG, "Signing operation failed!\n"); + + buf_move(data, out); + buf_free(out); + buf_free(r); + buf_free(s); + return (err); +} + +int pgp_elgdecrypt(BUFFER *in, BUFFER *key) +{ + BIGNUM *a = NULL, *b = NULL, *c = NULL, + *p = NULL, *g = NULL, *x = NULL; + BN_CTX *ctx; + BUFFER *i; + int err = -1; + + i = buf_new(); + ctx = BN_CTX_new(); + if (ctx == NULL) goto end; + mpi_get(key, i); + p = BN_bin2bn(i->data, i->length, NULL); + mpi_get(key, i); + g = BN_bin2bn(i->data, i->length, NULL); + mpi_get(key, i); /* y */ + mpi_get(key, i); + x = BN_bin2bn(i->data, i->length, NULL); + mpi_get(in, i); + a = BN_bin2bn(i->data, i->length, NULL); + if (mpi_get(in, i) == -1) + goto e1; + b = BN_bin2bn(i->data, i->length, NULL); + c = BN_new(); + + if (BN_mod_exp(c, a, x, p, ctx) == 0) goto end; + if (BN_mod_inverse(a, c, p, ctx) == 0) goto end; + if (BN_mod_mul(c, a, b, p, ctx) == 0) goto end; + + buf_prepare(i, BN_num_bytes(c)); + i->length = BN_bn2bin(c, i->data); + + buf_prepare(in, BN_num_bytes(c)); + in->length = RSA_padding_check_PKCS1_type_2(in->data, in->length, i->data, + i->length, i->length + 1); + if (in->length <= 0) + in->length = 0; + else + err = 0; + + end: + BN_free(b); + BN_free(c); + e1: + buf_free(i); + BN_free(a); + BN_free(p); + BN_free(g); + BN_clear_free(x); + BN_CTX_free(ctx); + + return (err); +} + +int pgp_elgencrypt(BUFFER *in, BUFFER *key) +{ + BIGNUM *m, *k, *a, *b, *c, *p, *g, *y = NULL; + BN_CTX *ctx; + BUFFER *i; + int err = -1; + + i = buf_new(); + ctx = BN_CTX_new(); + if (ctx == NULL) goto end; + mpi_get(key, i); + p = BN_bin2bn(i->data, i->length, NULL); + mpi_get(key, i); + g = BN_bin2bn(i->data, i->length, NULL); + if (mpi_get(key, i) == -1) + goto e1; + y = BN_bin2bn(i->data, i->length, NULL); + + buf_prepare(i, BN_num_bytes(p)); + if (RSA_padding_add_PKCS1_type_2(i->data, i->length, in->data, in->length) + != 1) + goto end; + m = BN_bin2bn(i->data, i->length, NULL); + + k = BN_new(); + BN_rand(k, BN_num_bits(p), 0, 0); + + a = BN_new(); + b = BN_new(); + c = BN_new(); + + if (BN_mod_exp(a, g, k, p, ctx) == 0) goto end; + if (BN_mod_exp(c, y, k, p, ctx) == 0) goto end; + if (BN_mod_mul(b, m, c, p, ctx) == 0) goto end; + + buf_clear(in); + i->length = BN_bn2bin(a, i->data); + mpi_put(in, i); + i->length = BN_bn2bin(b, i->data); + mpi_put(in, i); + + err = 0; + + BN_free(a); + BN_free(b); + BN_free(c); + BN_free(m); +e1: + buf_free(i); + BN_free(p); + BN_free(g); + BN_free(y); + BN_CTX_free(ctx); + end: + + return (err); +} + +#endif /* USE_PGP */ diff --git a/Src/pgpdb.c b/Src/pgpdb.c @@ -0,0 +1,583 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + OpenPGP key database + $Id: pgpdb.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#ifdef USE_PGP +#include "pgp.h" +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +static int pgp_readkeyring(BUFFER *keys, char *filename) +{ + FILE *keyfile; + BUFFER *armored, *line, *tmp; + int err = -1; + + if ((keyfile = mix_openfile(filename, "rb")) == NULL) + return (err); + + armored = buf_new(); + buf_read(armored, keyfile); + fclose(keyfile); + if (pgp_ispacket(armored)) { + err = 0; + buf_move(keys, armored); + } else { + line = buf_new(); + tmp = buf_new(); + + while (1) { + do + if (buf_getline(armored, line) == -1) { + goto end_greedy_dearmor; + } + while (!bufleft(line, begin_pgp)) ; + buf_clear(tmp); + buf_cat(tmp, line); + buf_appends(tmp, "\n"); + do { + if (buf_getline(armored, line) == -1) { + goto end_greedy_dearmor; + } + buf_cat(tmp, line); + buf_appends(tmp, "\n"); + } while (!bufleft(line, end_pgp)) ; + + if (pgp_dearmor(tmp, tmp) == 0) { + err = ARMORED; + buf_cat(keys, tmp); + } + } +end_greedy_dearmor: + buf_free(line); + buf_free(tmp); + + } + buf_free(armored); + return (err); +} + +KEYRING *pgpdb_open(char *keyring, BUFFER *encryptkey, int writer, int type) +{ + KEYRING *keydb; + + assert(! ((writer) && (type == PGP_TYPE_UNDEFINED))); + keydb = pgpdb_new(keyring, -1, encryptkey, type); +#ifndef NDEBUG + keydb->writer = writer; +#endif + if (writer) + keydb->lock = lockfile(keyring); + keydb->filetype = pgp_readkeyring(keydb->db, keyring); +#if 0 + if (keydb->filetype == -1) { + pgpdb_close(keydb); + return (NULL); + } +#endif /* if 0 */ + if (encryptkey && encryptkey->length && pgp_isconventional(keydb->db) && + pgp_decrypt(keydb->db, encryptkey, NULL, NULL, NULL) < 0) { + user_delpass(); + return (NULL); + } + return (keydb); +} + +KEYRING *pgpdb_new(char *keyring, int filetype, BUFFER *encryptkey, int type) +{ + KEYRING *keydb; + + keydb = malloc(sizeof(KEYRING)); + + if (keydb == NULL) + return NULL; + keydb->db = buf_new(); + keydb->modified = 0; + keydb->lock = NULL; + keydb->type = type; + strncpy(keydb->filename, keyring, sizeof(keydb->filename)); + keydb->filetype = filetype; + if (encryptkey == NULL) + keydb->encryptkey = NULL; + else { + keydb->encryptkey = buf_new(); + buf_set(keydb->encryptkey, encryptkey); + } + return (keydb); +} + +int pgpdb_close(KEYRING *keydb) +{ + int err = 0; + + if (keydb->modified) { + FILE *f; +#ifndef ndebug + assert(keydb->writer); +#endif + if (keydb->encryptkey && keydb->encryptkey->length) + pgp_encrypt(PGP_NCONVENTIONAL | PGP_NOARMOR, keydb->db, + keydb->encryptkey, NULL, NULL, NULL, NULL); + assert(keydb->type == PGP_TYPE_PRIVATE || keydb->type == PGP_TYPE_PUBLIC); + if (keydb->filetype == ARMORED) + pgp_armor(keydb->db, keydb->type == PGP_TYPE_PUBLIC ? PGP_ARMOR_KEY : PGP_ARMOR_SECKEY); + if (keydb->filetype == -1 || (f = mix_openfile(keydb->filename, + keydb->filetype == + ARMORED ? "w" : "wb")) + == NULL) + err = -1; + else { + err = buf_write(keydb->db, f); + fclose(f); + } + } + if (keydb->lock) + unlockfile(keydb->lock); + if (keydb->encryptkey) + buf_free(keydb->encryptkey); + buf_free(keydb->db); + free(keydb); + return (err); +} + +int pgpdb_getnext(KEYRING *keydb, BUFFER *key, BUFFER *keyid, BUFFER *userid) + /* store next key from keydb with specified keyid/userid in key. */ +{ + int found = 0; + int type; + long ptr; + int tempbuf = 0; + BUFFER *p, *i, *thisid; + + p = buf_new(); + i = buf_new(); + thisid = buf_new(); + + if (key == NULL) { + tempbuf = 1; + key = buf_new(); + } + assert(key != keyid); + while (!found) { + buf_clear(key); + type = pgp_getpacket(keydb->db, key); + if (type == -1) + break; + if (type != PGP_PUBKEY && type != PGP_SECKEY) + continue; + if ((keyid == NULL || keyid->length == 0) && + (userid == NULL || userid->length == 0)) + found = 1; + + if (keyid && keyid->length > 0) { + pgp_keyid(key, thisid); + if (buf_eq(keyid, thisid)) + found = 1; + } + + pgp_packet(key, type); + + while ((ptr = keydb->db->ptr, type = pgp_getpacket(keydb->db, p)) > 0) { + switch (type) { + case PGP_SECKEY: + case PGP_PUBKEY: + keydb->db->ptr = ptr; + goto nextkey; + case PGP_PUBSUBKEY: + case PGP_SECSUBKEY: + if (keyid && keyid->length > 0) { + pgp_keyid(p, thisid); + if (buf_eq(keyid, thisid)) + found = 1; + } + break; + case PGP_USERID: +#ifdef DEBUG + printf("%s\n", p->data); +#endif /* DEBUG */ + if (userid && userid->length > 0 && bufifind(p, userid->data)) + found = 1; + break; + } + pgp_packet(p, type); + buf_cat(key, p); + } + nextkey: + ; + } + if (tempbuf) + buf_free(key); + buf_free(p); + buf_free(i); + buf_free(thisid); + return (found ? 0 : -1); +} + +int pgpdb_append(KEYRING *keydb, BUFFER *p) +{ + assert(keydb->lock); +#ifndef ndebug + assert(keydb->writer); +#endif + buf_cat(keydb->db, p); + keydb->modified = 1; + return (0); +} + +#define pgp_preferredalgo PGP_ES_RSA + +int pgpdb_getkey(int mode, int algo, int *sym, int *mdc, long *expires, BUFFER *key, BUFFER *userid, + BUFFER *founduid, BUFFER *keyid, char *keyring, BUFFER *pass) +/* FIXME: This could be changed to return the key with the latest expiration date if + * a key is not unique */ +{ + KEYRING *r; + BUFFER *id, *thisid, *thiskey; + int thisalgo, algofound = -1, needpass = 0; + int found = 0; + + id = buf_new(); + thisid = buf_new(); + thiskey = buf_new(); + if (keyring) + r = pgpdb_open(keyring, pass, 0, PGP_TYPE_UNDEFINED); + else + switch (mode) { + case PK_DECRYPT: + case PK_SIGN: + r = pgpdb_open(PGPREMSECRING, NULL, 0, PGP_TYPE_PRIVATE); + break; + case PK_ENCRYPT: + case PK_VERIFY: + r = pgpdb_open(PGPREMPUBASC, NULL, 0, PGP_TYPE_PUBLIC); + if (r != NULL && r->filetype == -1) { + pgpdb_close(r); + r = pgpdb_open(PGPREMPUBRING, NULL, 0, PGP_TYPE_PUBLIC); + } + break; + default: + r = NULL; + } + if (r == NULL) + goto end; + + for (;;) { + /* repeat until success or end of key ring */ + if (pgpdb_getnext(r, thiskey, keyid, userid) == -1) + break; + if (keyid) /* pgp_getkey has to chose subkey with given keyid */ + buf_set(thisid, keyid); + thisalgo = pgp_getkey(mode, algo, sym, mdc, expires, thiskey, thiskey, thisid, founduid, + pass); + if (thisalgo == PGP_PASS) + needpass = 1; + if (thisalgo > 0) { + found++; + if ((thisalgo == pgp_preferredalgo && algofound != pgp_preferredalgo + && algofound > 0) + || (thisalgo != pgp_preferredalgo && algofound == pgp_preferredalgo)) + found--; /* ignore the non-preferred algorithm */ + if (found <= 1 || (thisalgo == pgp_preferredalgo && + algofound != pgp_preferredalgo && algofound > 0)) { + algofound = thisalgo; + if (key) + buf_move(key, thiskey); + buf_set(id, thisid); + } + } + } + pgpdb_close(r); +end: + if (found < 1) { + if (needpass) + errlog(DEBUGINFO, "Need passphrase!\n"); + else if (!sym || *sym != PGP_K_IDEA) { /* kludge: try again with 3DES */ + if (userid) + errlog(NOTICE, "Key %b not found!\n", userid); + else if (keyid && keyid->length > 7) + errlog(NOTICE, "Key %02X%02X%02X%02X not found!\n", keyid->data[4], + keyid->data[5], keyid->data[6], keyid->data[7]); + } + } + if (found > 1) { + if (userid) + errlog(WARNING, "Key %b not unique!\n", userid); + else if (keyid && keyid->length > 7) + errlog(ERRORMSG, "Key %02X%02X%02X%02X not unique!\n", keyid->data[4], + keyid->data[5], keyid->data[6], keyid->data[7]); + else + errlog(WARNING, "Key not unique!\n"); + } + if (found && keyid) /* return ID of found key */ + buf_set(keyid, id); + + buf_free(thiskey); + buf_free(thisid); + buf_free(id); + return (algofound); +} + +int pgp_keymgt(int force) +{ + FILE *f = NULL; + BUFFER *key, *keybak, *userid, *out, *outkey, *outtxt, *pass, *secout; + KEYRING *keys; + int err = 0, res, recreate_pubring = 0, dsa_ok = 0; +#ifdef USE_IDEA + int rsa_ok = 0; +#endif /* USE_IDEA */ + long expires; + LOCK *seclock; + + key = buf_new(); + out = buf_new(); + keybak = buf_new(); + secout = buf_new(); + + userid = buf_new(); + buf_sets(userid, REMAILERNAME); + pass = buf_new(); + buf_sets(pass, PASSPHRASE); + outtxt = buf_new(); + outkey = buf_new(); + + /* We only want to build RSA keys if we also can do IDEA + * This is to not lose any mail should users try our RSA key + * with IDEA. + */ +#ifdef USE_IDEA + /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring + * which probably works most of the time if the keys are in the correct order + * it doesn't return the latest expiration date (or 0) if the key in question + * is before another matching key in the keyring tho + */ + res = pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, &expires, NULL, NULL, + NULL, NULL, NULL, pass); + if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) { + rsa_ok = -1; + pgp_keygen(PGP_ES_RSA, 0, userid, pass, PGPKEY, PGPREMSECRING, 0); + }; + + if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, PGPKEY, NULL) < 0) && rsa_ok == 0) + rsa_ok = 1; +#endif /* USE_IDEA */ + /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring + * which probably works most of the time if the keys are in the correct order + * it doesn't return the latest expiration date (or 0) if the key in question + * is before another matching key in the keyring tho + */ + res = pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, &expires, NULL, NULL, + NULL, NULL, NULL, pass); + if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) { + dsa_ok = -1; + pgp_keygen(PGP_E_ELG, 0, userid, pass, PGPKEY, PGPREMSECRING, 0); + } + + if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, PGPKEY, NULL) > 0) && dsa_ok == 0) + dsa_ok = 1; + + /* No need to rewrite the files - we didn't change a thing */ + if ( +#ifdef USE_IDEA + rsa_ok == 1 && +#endif /* USE_IDEA */ + dsa_ok == 1) + goto end; + + /* write keys one key per armor to make hand editing easy and old PGP + * versions happy */ + err = -1; + keys = pgpdb_open(PGPKEY, NULL, 0, PGP_TYPE_PUBLIC); + if (keys == NULL) + recreate_pubring = 1; + else { + while (pgpdb_getnext(keys, key, NULL, userid) != -1) { + buf_clear(outtxt); + if (pgp_makekeyheader(PGP_PUBKEY, key, outtxt, NULL, PGP_ANY) == 0) { + err = 0; + buf_appends(out, "Type Bits/KeyID Date User ID\n"); + buf_cat(out, outtxt); + buf_nl(out); + pgp_armor(key, PGP_ARMOR_KEY); + buf_cat(out, key); + buf_nl(out); + } + } + pgpdb_close(keys); + } + if (err != 0) + recreate_pubring = 1; + err = -1; + + keys = pgpdb_open(PGPREMSECRING, NULL, 0, PGP_TYPE_PRIVATE); + if (keys == NULL) + goto end; + while (pgpdb_getnext(keys, key, NULL, userid) != -1) { + buf_clear(outtxt); + buf_clear(outkey); + buf_clear(keybak); + buf_cat(keybak, key); + if (pgp_makekeyheader(PGP_SECKEY, key, outtxt, pass, PGP_ANY) == 0) { + err = 0; + buf_appends(secout, "Type Bits/KeyID Date User ID\n"); + buf_cat(secout, outtxt); + buf_nl(secout); + pgp_armor(key, PGP_ARMOR_SECKEY); + buf_cat(secout, key); + buf_nl(secout); + } + buf_clear(outtxt); + if (recreate_pubring && + pgp_makepubkey(keybak, outtxt, outkey, pass, PGP_ANY) == 0) { + buf_appends(out, "Type Bits/KeyID Date User ID\n"); + buf_cat(out, outtxt); + buf_nl(out); + pgp_armor(outkey, PGP_ARMOR_KEY); + buf_cat(out, outkey); + buf_nl(out); + } + } + pgpdb_close(keys); + + seclock = lockfile(PGPREMSECRING); + if (err == 0 && (f = mix_openfile(PGPREMSECRING, "w")) != NULL) { + buf_write(secout, f); + fclose(f); + } else + err = -1; + unlockfile(seclock); + if (err == 0 && (f = mix_openfile(PGPKEY, "w")) != NULL) { + buf_write(out, f); + fclose(f); + } else + err = -1; +end: + buf_free(key); + buf_free(keybak); + buf_free(out); + buf_free(userid); + buf_free(pass); + buf_free(outtxt); + buf_free(outkey); + buf_free(secout); + return (err); +} + +int pgp_latestkeys(BUFFER* outtxt, int algo) +/* returns our latest key from pgpkey.txt in the buffer outtxt + * with pgp key header, ascii armored + * + * Can probably be extended to do this for all keys if we pass + * the keyring file and the userid + * + * IN: algo: PGP_ANY, PGP_ES_RSA, PGP_E_ELG, PGP_S_DSA + * OUT: outtxt + */ +{ + int err = -1; + long expires_found = 0, expires; + BUFFER *key, *userid, *tmptxt; + KEYRING *keys; + + key = buf_new(); + userid = buf_new(); + buf_sets(userid, REMAILERNAME); + tmptxt = buf_new(); + + keys = pgpdb_open(PGPKEY, NULL, 0, PGP_TYPE_PUBLIC); + if (keys != NULL) { + while (pgpdb_getnext(keys, key, NULL, userid) != -1) { + buf_clear(tmptxt); + if (pgp_makekeyheader(PGP_PUBKEY, key, tmptxt, NULL, algo) == 0) { + buf_rewind(key); + pgp_getkey(PK_VERIFY, algo, NULL, NULL, &expires, key, NULL, NULL, NULL, NULL); + if (expires == 0 || (expires_found <= expires)) { + err = 0; + buf_clear(outtxt); + buf_appends(outtxt, "Type Bits/KeyID Date User ID\n"); + buf_cat(outtxt, tmptxt); + buf_nl(outtxt); + pgp_armor(key, PGP_ARMOR_KEY); + buf_cat(outtxt, key); + buf_nl(outtxt); + expires_found = expires; + } + } + } + pgpdb_close(keys); + } + + buf_free(key); + buf_free(userid); + buf_free(tmptxt); + + return (err); +} + +int pgp_rlist(REMAILER remailer[], int n) + /* verify that keys are available */ +{ + BUFFER *keyring, *p; + int i, type, pgpkey[MAXREM]; + + keyring = buf_new(); + p = buf_new(); + for (i = 1; i < n; i++) + pgpkey[i] = 0; + if (pgp_readkeyring(keyring, PGPREMPUBASC) == -1) + pgp_readkeyring(keyring, PGPREMPUBRING); + while ((type = pgp_getpacket(keyring, p)) != -1) + if (type == PGP_USERID) + for (i = 1; i < n; i++) + if (remailer[i].flags.pgp && bufifind(p, remailer[i].name)) + pgpkey[i] = 1; + for (i = 1; i < n; i++) + remailer[i].flags.pgp = pgpkey[i]; + buf_free(p); + buf_free(keyring); + return (0); +} + +int pgp_rkeylist(REMAILER remailer[], int keyid[], int n) + /* Step through all remailers and get keyid */ +{ + BUFFER *userid; + BUFFER *id; + int i, err; + + userid = buf_new(); + id = buf_new(); + + for (i = 1; i < n; i++) { + buf_clear(userid); + buf_setf(userid, "<%s>", remailer[i].addr); + + keyid[i]=0; + if (remailer[i].flags.pgp) { + buf_clear(id); + err = pgpdb_getkey(PK_VERIFY, PGP_ANY, NULL, NULL, NULL, NULL, userid, NULL, id, NULL, NULL); + if (id->length == 8) { + /* printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n", + id->data[0], id->data[1], id->data[2], id->data[3], id->data[4], id->data[5], id->data[6], id->data[7], id->data[8], remailer[i].addr); */ + keyid[i] = (((((id->data[4] << 8) + id->data[5]) << 8) + id->data[6]) << 8) + id->data[7]; + } + } + } + + buf_free(userid); + return (0); +} + +#endif /* USE_PGP */ diff --git a/Src/pgpget.c b/Src/pgpget.c @@ -0,0 +1,870 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Read OpenPGP packets + $Id: pgpget.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#ifdef USE_PGP +#include "pgp.h" +#include "crypto.h" +#include <time.h> +#include <assert.h> +#include <string.h> + +int pgp_getmsg(BUFFER *in, BUFFER *key, BUFFER *sig, char *pubring, + char *secring) +{ + BUFFER *p; + BUFFER *out; + int type, algo = 0; + int err = PGP_NOMSG; + pgpsig signature = {0, NULL, 0, 0, {0,} }; + + p = buf_new(); + out = buf_new(); + + if (sig) + signature.userid = buf_new(); + + while ((type = pgp_getpacket(in, p)) > 0) + switch (type) { + case PGP_LITERAL: + pgp_getliteral(p); + buf_move(out, p); + err = 0; + break; + case PGP_COMPRESSED: + err = pgp_uncompress(p); + if (err == 0) + err = pgp_getmsg(p, key, sig, pubring, secring); + if (err != PGP_ERR && err != PGP_PASS) + buf_move(out, p); + break; + case PGP_ENCRYPTED: + case PGP_ENCRYPTEDMDC: + if (!key) { + err = -1; + break; + } + if (/*key->length > 0 &&*/ algo == 0) { + algo = PGP_K_IDEA; + digest_md5(key, key); + } + if (key->length > 0) + err = pgp_getsymmetric(p, key, algo, type==PGP_ENCRYPTEDMDC); + else + err = -1; + if (err == 0) + err = pgp_getmsg(p, NULL, sig, pubring, secring); + if (err != PGP_ERR) + buf_move(out, p); + break; + case PGP_SESKEY: + if (!key) { + err = -1; + break; + } + err = pgp_getsessionkey(p, key, secring); + if (err >= 0) { + algo = err; + err = 0; + buf_set(key, p); + } + break; + case PGP_SYMSESKEY: + if (!key) { + err = -1; + break; + } + err = pgp_getsymsessionkey(p, key); + if (err >= 0) { + algo = err; + err = 0; + if (key) buf_set(key, p); + } + break; + case PGP_MARKER: + err = 0; + break; /* ignore per RFC2440 */ + case PGP_SIG: + pgp_getsig(p, &signature, pubring); + /* fallthru */ + default: + if (err == PGP_NOMSG) + err = PGP_NODATA; + } + + if (signature.ok == PGP_SIGVRFY) + pgp_verify(out, sig, &signature); + if (signature.ok == PGP_SIGOK) { + char line[LINELEN]; + time_t t; + struct tm *tc; + + t = signature.sigtime; + tc = localtime(&t); +#if 0 + strftime(line, LINELEN, "[%Y-%m-%d %H:%M:%S]", tc); +#else /* end of 0 */ + strftime(line, LINELEN, "[%a %b %d %H:%M:%S %Y]", tc); +#endif /* else if not 0 */ + if (sig) { + buf_cat(sig, signature.userid); + buf_appendc(sig, ' '); + buf_appends(sig, line); + } + } + if (sig) { + if (signature.ok == PGP_SIGNKEY) + buf_appendf(sig, "%02X%02X%02X%02X", signature.userid->data[4], + signature.userid->data[5], signature.userid->data[6], + signature.userid->data[7]); + buf_free(signature.userid); + } + + if ((err == 0 || err == PGP_NODATA) && signature.ok != 0) + err = signature.ok; + + buf_move(in, out); + buf_free(out); + buf_free(p); + + return (err); +} + +int pgp_ispacket(BUFFER *b) +{ + return ((b->data[b->ptr] >> 6) == 2 || (b->data[b->ptr] >> 6) == 3); +} + +int pgp_packettype(BUFFER *b, long *len, int *partial) +{ + int ctb; + + ctb = buf_getc(b); + switch (ctb >> 6) { + case 2: + /* old packet type */ + switch (ctb & 3) { + case 0: + *len = buf_getc(b); + break; + case 1: + *len = buf_geti(b); + break; + case 2: + *len = buf_getl(b); + break; + case 3: + *len = b->length - b->ptr; + break; + } + *partial = 0; + return (ctb >> 2) & 15; + case 3: + case 1: /* in GnuPG secret key ring */ + /* new packet type */ + *len = buf_getc(b); + if (*len >= 192 && *len <= 223) + *len = (*len - 192) * 256 + buf_getc(b) + 192; + else if (*len == 255) + *len = buf_getl(b); + else if (*len > 223) { + *len = 1 <<(*len & 0x1f); + *partial = 1; + } + return (ctb & 63); + } + return (-1); +} + +int pgp_packetpartial(BUFFER *b, long *len, int *partial) +{ + *partial = 0; + *len = buf_getc(b); + if (*len >= 192 && *len <= 223) + *len = (*len - 192) * 256 + buf_getc(b) + 192; + else if (*len == 255) + *len = buf_getl(b); + else if (*len > 223) { + *len = 1 <<(*len & 0x1f); + *partial = 1; + } + return 1; +} + +int pgp_isconventional(BUFFER *b) +{ + int type; + BUFFER *p; + p = buf_new(); + + type = pgp_getpacket(b, p); + if (type == PGP_MARKER) + type = pgp_getpacket(b, p); + buf_rewind(b); + buf_free(p); + return (type == PGP_ENCRYPTED || type == PGP_SYMSESKEY); +} + +int pgp_getpacket(BUFFER *in, BUFFER *p) + /* returns <0 = error, >0 = packet type */ +{ + int type; + long len; + int partial = 0; + BUFFER *tmp; + + tmp = buf_new(); + type = pgp_packettype(in, &len, &partial); + if (type > 0 && len > 0) { + buf_clear(p); + while(partial && len > 0) { + buf_get(in, tmp, len); + buf_cat(p, tmp); + pgp_packetpartial(in, &len, &partial); + } + if (len > 0) { + buf_get(in, tmp, len); + buf_cat(p, tmp); + } + } + + buf_free(tmp); + return (type); +} + +int pgp_getsig(BUFFER *p, pgpsig *sig, char *pubring) +{ + BUFFER *sigkey, *id, *i; + int algo, hashalgo; + int hash; + + sigkey = buf_new(); + id = buf_new(); + i = buf_new(); + + sig->ok = PGP_SIGBAD; + + if (buf_getc(p) > 3) + goto end; + if (buf_getc(p) != 5) + goto end; + sig->sigtype = buf_getc(p); + sig->sigtime = buf_getl(p); + buf_get(p, id, 8); + algo = buf_getc(p); + hashalgo = buf_getc(p); + if (hashalgo != PGP_H_MD5) + goto end; + hash = buf_geti(p); + if (pgpdb_getkey(PK_VERIFY, algo, NULL, NULL, NULL, sigkey, NULL, sig->userid, id, + pubring, NULL) < 0) { + sig->ok = PGP_SIGNKEY; + if (sig->userid) + buf_set(sig->userid, id); + goto end; + } + switch (algo) { + case PGP_ES_RSA: + mpi_get(p, i); + if (pgp_rsa(i, sigkey, PK_VERIFY) == -1 || + memcmp(i->data, MD5PREFIX, sizeof(MD5PREFIX) - 1) != 0) + goto end; + memcpy(sig->hash, i->data + sizeof(MD5PREFIX) - 1, 16); + if (sig->hash[0] * 256 + sig->hash[1] != hash) + goto end; + sig->ok = PGP_SIGVRFY; + break; + default: + break; + } +end: + buf_free(sigkey); + buf_free(id); + buf_free(i); + return (sig->ok); +} + +void pgp_verify(BUFFER *msg, BUFFER *detached, pgpsig *sig) +{ + MD5_CTX c; + BUFFER *t; + byte md[16]; + + t = buf_new(); + sig->ok = PGP_SIGBAD; + + if (msg->length == 0) { /* detached signature */ + if (detached && detached->length) { + buf_move(msg, detached); + if (sig->sigtype == PGP_SIG_CANONIC) + pgp_sigcanonic(msg); /* for cleartext signatures */ + } else + sig->ok = PGP_NODATA; + } + MD5_Init(&c); + switch (sig->sigtype) { + case PGP_SIG_BINARY: + MD5_Update(&c, msg->data, msg->length); + break; + case PGP_SIG_CANONIC: + while (buf_getline(msg, t) != -1) { +#if 0 + pgp_sigcanonic(t); /* according to OpenPGP */ +#else /* end of 0 */ + buf_appends(t, "\r\n"); +#endif /* else if not 0 */ + MD5_Update(&c, t->data, t->length); + } + break; + default: + sig->ok = PGP_SIGBAD; + } + MD5_Update(&c, &(sig->sigtype), 1); + buf_appendl(t, sig->sigtime); + MD5_Update(&c, t->data, 4); + MD5_Final(md, &c); + if (memcmp(md, sig->hash, 16) == 0) + sig->ok = PGP_SIGOK; + buf_free(t); +} + +#ifdef USE_IDEA +static int pgp_ideadecrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + int err = 0; + byte iv[8]; + byte hdr[10]; + int i, n; + IDEA_KEY_SCHEDULE ks; + SHA_CTX c; + char md[20]; /* we could make hdr 20 bytes long and reuse it for md */ + + if (key->length != 16 || in->length <= (mdc?(1+10+22):10)) + return (-1); + + if (mdc) { + mdc = 1; + if (in->data[0] != 1) + return (-1); + } + + buf_prepare(out, in->length - 10 - mdc); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + idea_set_encrypt_key(key->data, &ks); + + n = 0; + idea_cfb64_encrypt(in->data + mdc, hdr, 10, &ks, iv, &n, IDEA_DECRYPT); + if (n != 2 || hdr[8] != hdr[6] || hdr[9] != hdr[7]) { + err = -1; + goto end; + } + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, hdr, 10); + } else { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, in->data + 2, 6); + n = 0; + } + idea_cfb64_encrypt(in->data + 10 + mdc, out->data, in->length - 10 - mdc, &ks, iv, &n, + IDEA_DECRYPT); + if (mdc) { + if (out->length > 22) { + out->length -= 22; + if (out->data[out->length] == 0xD3 && out->data[out->length + 1] == 0x14) { + SHA1_Update(&c, out->data, out->length + 2); + SHA1_Final(md, &c); + if (memcmp(out->data + out->length + 2, md, 20)) + err = -1; + } else + err = -1; + } else + err = -1; + } +end: + return (err); +} +#endif /* USE_IDEA */ + +static int pgp_3desdecrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + int err = 0; + des_cblock iv; + byte hdr[10]; + int i, n; + des_key_schedule ks1; + des_key_schedule ks2; + des_key_schedule ks3; + SHA_CTX c; + char md[20]; /* we could make hdr 20 bytes long and reuse it for md */ + + if (key->length != 24 || in->length <= (mdc?(1+10+22):10)) + return (-1); + + if (mdc) { + mdc = 1; + if (in->data[0] != 1) + return (-1); + } + + buf_prepare(out, in->length - 10 - mdc); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + des_set_key((const_des_cblock *) key->data, ks1); + des_set_key((const_des_cblock *) (key->data + 8), ks2); + des_set_key((const_des_cblock *) (key->data+ 16), ks3); + + n = 0; + des_ede3_cfb64_encrypt(in->data + mdc, hdr, 10, ks1, ks2, ks3, &iv, &n, DECRYPT); + if (n != 2 || hdr[8] != hdr[6] || hdr[9] != hdr[7]) { + err = -1; + goto end; + } + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, hdr, 10); + } else { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, in->data + 2, 6); + n = 0; + } + des_ede3_cfb64_encrypt(in->data + 10 + mdc, out->data, in->length - 10 + mdc, ks1, + ks2, ks3, &iv, &n, DECRYPT); + if (mdc) { + if (out->length > 22) { + out->length -= 22; + if (out->data[out->length] == 0xD3 && out->data[out->length + 1] == 0x14) { + SHA1_Update(&c, out->data, out->length + 2); + SHA1_Final(md, &c); + if (memcmp(out->data + out->length + 2, md, 20)) + err = -1; + } else + err = -1; + } else + err = -1; + } +end: + return (err); +} + +static int pgp_castdecrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + int err = 0; + byte iv[8]; + byte hdr[10]; + int i, n; + SHA_CTX c; + char md[20]; /* we could make hdr 20 bytes long and reuse it for md */ + + CAST_KEY ks; + + if (key->length != 16 || in->length <= (mdc?(1+10+22):10)) + return (-1); + + if (mdc) { + mdc = 1; + if (in->data[0] != 1) + return (-1); + } + + buf_prepare(out, in->length - 10 - mdc); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + CAST_set_key(&ks, 16, key->data); + + n = 0; + CAST_cfb64_encrypt(in->data + mdc, hdr, 10, &ks, iv, &n, CAST_DECRYPT); + if (n != 2 || hdr[8] != hdr[6] || hdr[9] != hdr[7]) { + err = -1; + goto end; + } + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, hdr, 10); + } else { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, in->data + 2, 6); + n = 0; + } + CAST_cfb64_encrypt(in->data + 10 + mdc, out->data, in->length - 10 - mdc, &ks, + iv, &n, CAST_DECRYPT); + if (mdc) { + if (out->length > 22) { + out->length -= 22; + if (out->data[out->length] == 0xD3 && out->data[out->length + 1] == 0x14) { + SHA1_Update(&c, out->data, out->length + 2); + SHA1_Final(md, &c); + if (memcmp(out->data + out->length + 2, md, 20)) + err = -1; + } else + err = -1; + } else + err = -1; + } +end: + return (err); +} + +static int pgp_bfdecrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + int err = 0; + byte iv[8]; + byte hdr[10]; + int i, n; + SHA_CTX c; + char md[20]; /* we could make hdr 20 bytes long and reuse it for md */ + + BF_KEY ks; + + if (key->length != 16 || in->length <= (mdc?(1+10+22):10)) + return (-1); + + if (mdc) { + mdc = 1; + if (in->data[0] != 1) + return (-1); + } + + buf_prepare(out, in->length - 10 - mdc); + + for (i = 0; i < 8; i++) + iv[i] = 0; + + BF_set_key(&ks, 16, key->data); + + n = 0; + BF_cfb64_encrypt(in->data + mdc, hdr, 10, &ks, iv, &n, BF_DECRYPT); + if (n != 2 || hdr[8] != hdr[6] || hdr[9] != hdr[7]) { + err = -1; + goto end; + } + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, hdr, 10); + } else { + iv[6] = iv[0], iv[7] = iv[1]; + memcpy(iv, in->data + 2, 6); + n = 0; + } + BF_cfb64_encrypt(in->data + 10 + mdc, out->data, in->length - 10 - mdc, &ks, + iv, &n, BF_DECRYPT); + if (mdc) { + if (out->length > 22) { + out->length -= 22; + if (out->data[out->length] == 0xD3 && out->data[out->length + 1] == 0x14) { + SHA1_Update(&c, out->data, out->length + 2); + SHA1_Final(md, &c); + if (memcmp(out->data + out->length + 2, md, 20)) + err = -1; + } else + err = -1; + } else + err = -1; + } +end: + return (err); +} + +#ifdef USE_AES +static int pgp_aesdecrypt(BUFFER *in, BUFFER *out, BUFFER *key, int mdc) +{ + int err = 0; + byte iv[16]; + byte hdr[18]; + int i, n; + SHA_CTX c; + char md[20]; /* we could make hdr 20 bytes long and reuse it for md */ + + AES_KEY ks; + + if ((key->length != 16 && key->length != 24 && key->length != 32) || in->length <= (mdc?(1+18+22):18)) + return (-1); + + if (mdc) { + mdc = 1; + if (in->data[0] != 1) + return (-1); + } + + buf_prepare(out, in->length - 18 - mdc); + + for (i = 0; i < 16; i++) + iv[i] = 0; + + AES_set_encrypt_key(key->data, key->length<<3, &ks); + + n = 0; + AES_cfb128_encrypt(in->data + mdc, hdr, 18, &ks, iv, &n, AES_DECRYPT); + if (n != 2 || hdr[16] != hdr[14] || hdr[17] != hdr[15]) { + err = -1; + goto end; + } + if (mdc) { + SHA1_Init(&c); + SHA1_Update(&c, hdr, 18); + } else { + iv[14] = iv[0], iv[15] = iv[1]; + memcpy(iv, in->data + 2, 14); + n = 0; + } + AES_cfb128_encrypt(in->data + 18 + mdc, out->data, in->length - 18 - mdc, &ks, + iv, &n, AES_DECRYPT); + if (mdc) { + if (out->length > 22) { + out->length -= 22; + if (out->data[out->length] == 0xD3 && out->data[out->length + 1] == 0x14) { + SHA1_Update(&c, out->data, out->length + 2); + SHA1_Final(md, &c); + if (memcmp(out->data + out->length + 2, md, 20)) + err = -1; + } else + err = -1; + } else + err = -1; + } +end: + return (err); +} +#endif /* USE_AES */ + +int pgp_getsymmetric(BUFFER *in, BUFFER *key, int algo, int mdc) +{ + int err = -1; + BUFFER *out; + + out = buf_new(); + + switch (algo) { +#ifdef USE_AES + case PGP_K_AES128: + case PGP_K_AES192: + case PGP_K_AES256: + err = pgp_aesdecrypt(in, out, key, mdc); + break; +#endif /* USE_AES */ +#ifdef USE_IDEA + case PGP_K_IDEA: + err = pgp_ideadecrypt(in, out, key, mdc); + break; +#endif /* USE_IDEA */ + case PGP_K_3DES: + err = pgp_3desdecrypt(in, out, key, mdc); + break; + case PGP_K_CAST5: + err = pgp_castdecrypt(in, out, key, mdc); + break; + case PGP_K_BF: + err = pgp_bfdecrypt(in, out, key, mdc); + break; + } + + if (err < 0) + errlog(ERRORMSG, "PGP decryption failed.\n"); + + buf_move(in, out); + buf_free(out); + return (err); +} + +int pgp_getliteral(BUFFER *in) +{ + long fnlen; + int err = 0; + int mode; + BUFFER *out; + BUFFER *line; + + out = buf_new(); + line = buf_new(); + mode = buf_getc(in); + fnlen = buf_getc(in); + in->ptr += fnlen; /* skip filename */ + if (in->ptr + 4 > in->length) + err = -1; + else { + buf_getl(in); /* timestamp */ + if (mode == 't') + while (buf_getline(in, line) != -1) { + buf_cat(out, line); + buf_nl(out); + } else + buf_rest(out, in); + } + buf_move(in, out); + buf_free(line); + buf_free(out); + return (err); +} + +int pgp_uncompress(BUFFER *in) +{ + int err = -1; + + switch(buf_getc(in)) { + case 0: + err = 0; + break; + case 1: + err = buf_unzip(in, 0); + break; + case 2: + err = buf_unzip(in, 1); + break; + default: + err = -1; + break; + } + return (err); +} + +int pgp_getsessionkey(BUFFER *in, BUFFER *pass, char *secring) +{ + BUFFER *out; + BUFFER *key; + BUFFER *keyid; + int type; + int i, csum = 0; + int algo = 0; + int err = -1; + long expires; + + out = buf_new(); + key = buf_new(); + keyid = buf_new(); + type = buf_getc(in); /* packet type */ + if (type < 2 || type > 3) + goto end; + buf_get(in, keyid, 8); + algo = buf_getc(in); + err = pgpdb_getkey(PK_DECRYPT, algo, NULL, NULL, &expires, key, NULL, NULL, keyid, + secring, pass); + if (err < 0) + goto end; + if (expires > 0 && (expires + KEYGRACEPERIOD < time(NULL))) { + errlog(DEBUGINFO, "Key expired.\n"); /* DEBUGINFO ? */ + err = -1; + goto end; + } + switch (algo) { + case PGP_ES_RSA: + mpi_get(in, out); + err = pgp_rsa(out, key, PK_DECRYPT); + break; + case PGP_E_ELG: + buf_rest(out, in); + err = pgp_elgdecrypt(out, key); + break; + default: + err = -1; + } + if (err == 0 && out->length > 3) { + algo = buf_getc(out); + buf_get(out, in, out->length - 3); /* return recovered key */ + csum = buf_geti(out); + for (i = 0; i < in->length; i++) + csum = (csum - in->data[i]) % 65536; + if (csum != 0) + err = -1; + } else + err = -1; +end: + buf_free(out); + buf_free(key); + buf_free(keyid); + return (err == 0 ? algo : err); +} + +void pgp_iteratedsk(BUFFER *out, BUFFER *salt, BUFFER *pass, byte c) +{ + int count; + BUFFER *temp; + temp = buf_new(); + + count = (16l + (c & 15)) << ((c >> 4) + 6); + while (temp->length < count) { + buf_cat(temp, salt); + buf_cat(temp, pass); + } + buf_get(temp, out, count); + buf_free(temp); +} + +int pgp_getsk(BUFFER *p, BUFFER *pass, BUFFER *key) +{ + int skalgo, skspecifier, hashalgo; + BUFFER *salted; /* passphrase with salt */ + + if (!pass) + return(-1); + + salted = buf_new(); + + skalgo = buf_getc(p); + skspecifier = buf_getc(p); + hashalgo = buf_getc(p); + switch (skspecifier) { + case 0: + buf_set(salted, pass); + break; + case 1: + buf_get(p, salted, 8); /* salt */ + buf_cat(salted, pass); + break; + case 3: + buf_get(p, salted, 8); /* salt */ + pgp_iteratedsk(salted, salted, pass, buf_getc(p)); + break; + default: + skalgo = -1; + goto end; + } + if (pgp_expandsk(key, skalgo, hashalgo, salted) == -1) + skalgo = -1; + + end: + buf_free(salted); + return (skalgo); +} + +int pgp_getsymsessionkey(BUFFER *in, BUFFER *pass) +{ + BUFFER *temp, *key, *iv; + int algo = -1; + temp = buf_new(); + key = buf_new(); + iv = buf_new(); + + if (buf_getc(in) == 4) { /* version */ + algo = pgp_getsk(in, pass, key); + buf_rest(temp, in); + if (temp->length) { + /* encrypted session key present */ + buf_appendzero(iv, pgp_blocklen(algo)); + skcrypt(temp, algo, key, iv, DECRYPT); + algo = buf_getc(temp); + buf_rest(in, temp); + } else + buf_set(in, key); + } + buf_free(temp); + buf_free(key); + buf_free(iv); + return (algo); +} + +#endif /* USE_PGP */ diff --git a/Src/pool.c b/Src/pool.c @@ -0,0 +1,981 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Send messages from pool + $Id: pool.c 934 2006-06-24 13:40:39Z rabbi $ */ + +#include "mix3.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <time.h> +#ifdef POSIX +#include <unistd.h> +#else /* end of POSIX */ +#include <io.h> +#endif /* else if not POSIX */ +#ifndef _MSC +#include <dirent.h> +#endif /* not _MSC */ +#include <assert.h> +#include <sys/stat.h> +#include <sys/types.h> + +#ifdef USE_PCRE +#include "pcre.h" +#endif /* USE_PCRE */ + +int msg_send(char *name); + +int mix_send(void) +{ + return (mix_regular(FORCE_POOL)); +} + +/* Message pool: Unix DOS + * latent messages: l* *.lat + * pooled messages: m* *.msg + * messages to be sent: s* *.snd + * temporary files: t* *.tmp + * files in user editor: x* + * incoming mail: i* *.inf + * partial messages: p* p*.* + * error messages: e* *.err + * outgoing messages: out *.txt (to be used by external program) + */ + +static int is(char *path, char *type) +{ +#ifdef SHORTNAMES + int s; + + s = strlen(path); + if (s <= 4) + return 0; + return (path[s - 4] == '.' && streq(path + s - 3, type)); +#else /* end of SHORTNAMES */ + return (path[0] == type[0]); +#endif /* else if not SHORTNAMES */ +} + +static void mv(char *name, char *newtype) +{ + char old[PATHMAX], new[PATHMAX]; + + sprintf(old, "%s%c%s", POOLDIR, DIRSEP, name); +#ifdef SHORTNAMES + assert(strlen(name) > 4); + strcpy(name + strlen(name) - 3, newtype); +#else /* end of SHORTNAMES */ + name[0] = newtype[0]; +#endif /* else if not SHORTNAMES */ + sprintf(new, "%s%c%s", POOLDIR, DIRSEP, name); + rename(old, new); +} + +int latent_read(void) +{ + char path[PATHMAX]; + DIR *d; + FILE *f; + struct dirent *e; + int size = 0; + long now, then; + + now = time(NULL); + d = opendir(POOLDIR); + if (d != NULL) + for (;;) { + e = readdir(d); + if (e == NULL) + break; + if (is(e->d_name, "lat")) { + sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name); + f = fopen(path, "rb"); + if (f != NULL) { + fscanf(f, "%*d %ld\n", &then); + fclose(f); + if (now > then) + mv(e->d_name, "msg"); + } + } + } + closedir(d); + return (size); +} + +int infile_read(void) +{ + char path[PATHMAX]; + BUFFER *msg; + DIR *d; + FILE *f; + struct dirent *e; + int size = 0; + + msg = buf_new(); + d = opendir(POOLDIR); + if (d != NULL) + for (;;) { + e = readdir(d); + if (e == NULL) + break; + if (is(e->d_name, "inf")) { + mv(e->d_name, "tmp"); + sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name); + f = fopen(path, "rb"); + if (f != NULL) { + buf_clear(msg); + buf_read(msg, f); + fclose(f); + unlink(path); + mix_decrypt(msg); + } + } + } + closedir(d); + buf_free(msg); + return (size); +} + +int mailin_maildir_one(char *dir) +/** Read mails from one directory + This function reads all files from the directory passed and passes + them on to mix_decrypt(). Each file is unlinked when its is read. + + @param dir The directory in which files are to be read. No path finding + voodoo is done to the path; It's passed it opendir() as is. + @author PP + @return Number of files read + */ +{ + BUFFER *msg; + DIR *d; + FILE *f; + struct dirent *e; + int size = 0; + char path[PATHMAX]; + + msg = buf_new(); + d = opendir(dir); + if (d != NULL) + for (;;) { + e = readdir(d); + if (e == NULL) + break; + if (e->d_name[0] != '.') { + sprintf(path, "%s%c%s", dir, DIRSEP, e->d_name); + path[PATHMAX-1]='\0'; + f = fopen(path, "rb"); + if (f != NULL) { + buf_clear(msg); + buf_read(msg, f); + fclose(f); + unlink(path); + mix_decrypt(msg); + size++; + } + } + } + closedir(d); + buf_free(msg); + return (size); +} + +int mailin_maildir(char *maildir) +/** Read mails from a mail folder in Maildir format + Reads all files from the Maildir using mailin_maildir_one(). + All mails are removed after this function returns. + + @param maildir The Maildir to open. mixfile() is called to normalize the path. + @author PP + @return 0 + */ +{ + char normalized[PATHMAX]; + char path[PATHMAX]; + + mixfile(normalized, maildir); + sprintf(path, "%s%c%s", normalized, DIRSEP, "new"); + path[PATHMAX-1]='\0'; + mailin_maildir_one(path); + sprintf(path, "%s%c%s", normalized, DIRSEP, "cur"); + path[PATHMAX-1]='\0'; + mailin_maildir_one(path); + return (0); +} + +int mailin_mbox(char *path) +/** Read mails from a mail folder in mbox format + Reads all messages from the mbox filder passes as an argument. Mails are + handed over to mix_decrypt. After all mails have been read the mailbox + is truncated to zero size i.e. all mails are deleted. The mbox is + locked using lock() and unlock() during this operation. + + @param maildir Path to the mbox mail folder. + @author PP + @return 0 on sucess, other on error + */ +{ + char line[LINELEN]; + FILE *f; + int state, eof; + BUFFER *msg; + int err=0; + + msg = buf_new(); + + f = mix_openfile(path, "r+"); + if (f != NULL) { + if (lock(f) != 0) { + /* Locking failed */ + err = 1; + goto end; + } + /* State machine + * 1 - Look for the first ^From_ line + * 2 - add messages as they come + */ + state = 1; + eof = 0; + for(;;) { + if (fgets(line, sizeof(line), f) == NULL) + eof = 1; + + switch (state) { + case 1: + /* Initial state - Looking for first appearance of From_ */ + if (eof) + goto end_state; + if (strleft(line, "From ")) { +#if 0 + buf_appends(msg, line); +#endif /* 0 */ + state = 2; + break; + }; + break; + case 2: + /* Within one mail - Adding lines to mail until we encounter another From_ or eof */ + if (eof || strleft(line, "From ")) { + mix_decrypt(msg); + buf_clear(msg); + } + if (eof) + goto end_state; + if (!strleft(line, "From ")) + buf_appends(msg, line); + break; + default: + assert(0); + err=1; + goto end_state; + } + } +end_state: +#ifndef WIN32 + rewind(f); + ftruncate(fileno(f), 0); +#else /* end of not WIN32 */ + chsize(fileno(f), 0); +#endif /* else if WIN32 */ + unlock(f); + fclose(f); + } +end: + buf_free(msg); + return (err); +} + +/** Process MAILIN if applicable + If MAILIN is defined this function calls either mailin_maildir() or + mailin_mbox() depending on whether the last character of MAILIN + is DIRSEP. + + @param mailbox Path to the mbox or Maildir mail folder. + @author PP + @return 0 on sucess, other on error + */ +int mailin(char *mailbox) +{ + if (mailbox != NULL && (strcmp(mailbox, "") != 0)) + if (mailbox[strlen(mailbox)-1] == DIRSEP) + return mailin_maildir(mailbox); + else + return mailin_mbox(mailbox); + else + return 0; +}; + +int pool_add(BUFFER *msg, char *type) +{ + char path[PATHMAX], pathtmp[PATHMAX]; + FILE *f; + int err = -1; + + f = pool_new(type, pathtmp, path); + if (f != NULL) { + err = buf_write(msg, f); + fclose(f); + } + if (err == 0) { + rename(pathtmp, path); + errlog(DEBUGINFO, "Added %s file to pool.\n", type); + } + return (err); + +} + +FILE *pool_new(char *type, char *tmpname, char *path) +{ + FILE *f; + struct stat buf; + int err; + + assert(strlen(type) == 3); +#ifdef SHORTNAMES + sprintf(tmpname, "%s%c%02x%02x%02x%02x.tmp", POOLDIR, DIRSEP, rnd_byte(), rnd_byte(), + rnd_byte(), rnd_byte()); + strcpy(path, tmpname); + memcpy(path + strlen(path) - 3, type, 3); +#else /* end of SHORTNAMES */ + sprintf(tmpname, "%s%ct%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP, rnd_byte(), + rnd_byte(), rnd_byte(), rnd_byte(), rnd_byte(), + rnd_byte(), rnd_byte() & 15); + strcpy(path, tmpname); + strrchr(path, DIRSEP)[1] = type[0]; +#endif /* else if not SHORTNAMES */ + err = stat(tmpname, &buf); + if (err == 0) + errlog(WARNING, "Overwriting file %s\n", tmpname); + f = fopen(tmpname, "wb"); + if (f == NULL) + errlog(ERRORMSG, "Error creating temporary file %s\n", tmpname); + return (f); +} + +int pool_read(BUFFER *pool) +{ + DIR *d; + struct dirent *e; + int size = 0; + + d = opendir(POOLDIR); + if (d != NULL) { + for (;;) { + e = readdir(d); + if (e == NULL) + break; + if (is(e->d_name, "msg")) { + if (pool != NULL) { + buf_appends(pool, e->d_name); + buf_appendc(pool, 0); + } + size++; + } + } + closedir(d); + } else + errlog(WARNING, "Error reading pool dir %s\n", POOLDIR); + return (size); +} + +void pool_dosend(void) +{ + DIR *d; + struct dirent *e; + char path[PATHMAX]; + + d = opendir(POOLDIR); + if (d != NULL) { + for (;;) { + e = readdir(d); + if (e == NULL) + break; + if (is(e->d_name, "snd")) { + sendmail_begin(); + mv(e->d_name, "tmp"); + sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name); + if (msg_send(path) == 1) + mv(e->d_name, "err"); + } + } + closedir(d); + } else + errlog(WARNING, "Error reading pool dir %s\n", POOLDIR); + sendmail_end(); +} + +int process_mailin() +{ + mailin(MAILIN); + infile_read(); + return(0); +} + +int create_dummy_mailout() +{ + while (rnd_number(100) < OUTDUMMYP) { + errlog(DEBUGINFO, "Generating dummy message with outgoing mail.\n"); + if (mix_encrypt(MSG_NULL, NULL, NULL, 1, NULL) == -1) + return -1; + } + return 0; +} + +int pool_send(void) +{ + int size, max, i, r; + BUFFER *pool; + long int *ptr; + + create_dummy_mailout(); + + latent_read(); + pool = buf_new(); + size = pool_read(pool); + if (size <= POOLSIZE) + goto end; + + ptr = malloc(size * sizeof(long int)); + + if (ptr == NULL) + goto end; + for (i = 0; i < size; i++) { + ptr[i] = pool->ptr; + buf_getline(pool, NULL); + } + + max = size * RATE / 100; /* send no more than RATE % of the messages */ + if (max < 0) + max = 1; + + for (i = 0; i < size - POOLSIZE && i < max; i++) { + do + r = rnd_number(size); /* chose a new random message */ + while (is(pool->data + ptr[r], "snd")); + mv(pool->data + ptr[r], "snd"); + } + stats_out(size - --i); + pool_dosend(); + free(ptr); + +end: + buf_free(pool); + return (size); +} + +int msg_send(char *name) +{ + FILE *f; + int type = -1; + BUFFER *m, *addr; + int err = 0; + char line[LINELEN]; + int userfrom = 0; + + m = buf_new(); + addr = buf_new(); + if ((f = fopen(name, "rb")) == NULL) { + err = -1; + goto end; + } + fscanf(f, "%d %*d\n", &type); + if (type == INTERMEDIATE) { + fgets(line, sizeof(line), f); + buf_sets(addr, line); + buf_chop(addr); + err = buf_read(m, f); + if (err == -1) + goto end; + err = mix_armor(m); + if (err == -1) + goto end; + err = sendmail(m, REMAILERADDR, addr); + stats_log(3); + } else if (type == MSG_MAIL || type == MSG_POST) { + err = buf_read(m, f); + if (err == -1) + goto end; + if (MIDDLEMAN && ! allowmessage(m)) { + mix2_encrypt(type, m, FORWARDTO, 1, 1, NULL); + stats_log(6); + } else { + err = filtermsg(m); + if (err == 1) + userfrom = 1, err = 0; + if (err != -1) { + /* message has recipients */ + errlog(DEBUGINFO, "Sending message (%ld bytes)\n", m->length); + + if (type == MSG_MAIL) { + err = sendmail(m, userfrom ? NULL : ANONNAME, NULL); + stats_log(4); + } else if (type == MSG_POST) { + if (strchr(NEWS, '@') && !strchr(NEWS, ' ')) { + errlog(LOG, "Mailing article to %s.\n", NEWS); + buf_sets(addr, NEWS); + err = sendmail(m, userfrom ? NULL : ANONNAME, addr); + } else if (NEWS[0] != '\0') { + FILE *f; + + f = openpipe(NEWS); + if (f == NULL) + goto end; + errlog(LOG, "Posting article.\n"); + if (!userfrom) + fprintf(f, "From: %s\n", ANONNAME); + if (ORGANIZATION[0] != '\0') + fprintf(f, "Organization: %s\n", ORGANIZATION); + buf_write(m, f); + closepipe(f); + } else + errlog(NOTICE, "Rejecting news article.\n"); + stats_log(5); + } + } else + errlog(ERRORMSG, "Bad message file.\n"); + } + } +end: + if (f != NULL) + fclose(f); + if (err != 1) /* problem sending mail */ + unlink(name); + buf_free(m); + buf_free(addr); + return (err); +} + +int allowmessage(BUFFER *in) +/* Only called if remailer is middleman. Checks whether all Recipient + * addresses are in dest.allow. If yes return 1; 0 otherwhise + */ +{ + BUFFER *out, *allow, *allow2, *line, *line2; + int err=1; + FILE *f; + + allow = buf_new(); + allow2 = buf_new(); + out = buf_new(); + line = buf_new(); + line2 = buf_new(); + + f = mix_openfile(DESTALLOW, "r"); + if (f != NULL) { + buf_read(allow, f); + fclose(f); + } + f = mix_openfile(DESTALLOW2, "r"); + if (f != NULL) { + buf_read(allow2, f); + fclose(f); + buf_cat(allow, allow2); + } + + /* Do header lines */ + while (buf_getline(in, line) == 0) { + for (;;) { + buf_lookahead(in, line2); + if (!bufleft(line2, " ") && !bufleft(line2, "\t")) + break; + buf_getline(in, line2); + buf_cat(line, line2); + } + + if (bufileft(line, "to:") || bufileft(line, "cc:") || + bufileft(line, "bcc:") || bufileft(line, "newsgroups:")) + if (! doallow(line, allow)) + err = 0; + + if (line->length > 0) { + if (!buffind(line, ":")) + buf_appends(out, "X-Invalid: "); + buf_cat(out, line); + buf_nl(out); + } + } + buf_nl(out); + + /* Rest of the message */ + buf_append(out, in->data + in->ptr, in->length - in->ptr); + + buf_move(in, out); + buf_free(out); + buf_free(allow); + buf_free(allow2); + buf_free(line); + buf_free(line2); + return (err); +} + +int doallow(BUFFER *line, BUFFER *filter) +/* line is a To, CC or BCC line. + * problem is: there may be multiple addresses in one header + * line but we only want to allow if _all_ are allowed + * + * So to not send direct if we do not want, we _never_ send + * direct if there is more than one address: This is + * assumed to be the case when there is a + * comma in the header line. + * + * this should probably be rewritten somehwhen. therefore: FIXME + * + * returns: 1 if allowed + * 0 if message should be send indirectly + */ +{ + if (strchr( line->data, ',')) return 0; + return doblock(line, filter, 0); +} + +int filtermsg(BUFFER *in) +{ + BUFFER *out, *line, *line2, *mboundary, *block, *filter, *mid; + FILE *f; + int from = 0, dest = 0; + int inbinary = 0, inpgp = 0, l = 80; + int err = -1; + + line = buf_new(); + line2 = buf_new(); + filter = buf_new(); + mid = buf_new(); + mboundary = buf_new(); + out = buf_new(); + block = NULL; + + if (SIZELIMIT > 0 && in->length > SIZELIMIT * 1024) { + errlog(NOTICE, "Message rejected: %ld bytes\n", in->length); + goto end; + } + + block = readdestblk( ); + if ( !block ) block = buf_new( ); + + f = mix_openfile(HDRFILTER, "r"); + if (f != NULL) { + buf_read(filter, f); + fclose(f); + } + + f = mix_openfile(DISCLAIMFILE, "r"); + if (f != NULL) { + buf_read(out, f); + fclose(f); + } else { + if (strfind(DISCLAIMER, "%s")) + buf_appendf(out, DISCLAIMER, COMPLAINTS); + else + buf_appends(out, DISCLAIMER); + } + + while (buf_getline(in, line) == 0) { + for (;;) { + buf_lookahead(in, line2); + if (!bufleft(line2, " ") && !bufleft(line2, "\t")) + break; + buf_getline(in, line2); + buf_cat(line, line2); + } + + if (bufileft(line, "to:") || bufileft(line, "cc:") || + bufileft(line, "bcc:") || bufileft(line, "newsgroups:")) + if (doblock(line, block, 1) == 0) + dest++; + if (doblock(line, filter, 1) == -1) + goto end; + if (bufileft(line, "from:")) + from = 1; + + if (bufileft(line, "content-type:") && bufileft(line, "multipart")) + get_parameter(line, "boundary", mboundary); + + if (line->length > 0) { + if (!buffind(line, ":")) + buf_appends(out, "X-Invalid: "); + buf_cat(out, line); + buf_nl(out); + } + } + + if (MID[0] != '\0' && tolower(MID[0]) != 'n') { + char txt[LINELEN]; + + digestmem_md5(in->data + in->ptr, in->length - in->ptr, mid); + id_encode(mid->data, txt); + + if (MID[0] == '@') + strcatn(txt, MID, sizeof(txt)); + else { + if (strchr(REMAILERADDR, '@')) + strcatn(txt, strchr(REMAILERADDR, '@'), sizeof(txt)); + else if (strchr(COMPLAINTS, '@')) + strcatn(txt, strchr(COMPLAINTS, '@'), sizeof(txt)); + } + buf_appendf(out, "Message-ID: <%s>\n", txt); + } + buf_nl(out); + + if (from) { + /* prepend Sender line to message header */ + buf_setf(line, "Sender: %s\n", ANONNAME); + buf_cat(line, out); + buf_move(out, line); + + f = mix_openfile(FROMDSCLFILE, "r"); + if (f != NULL) { + buf_read(out, f); + fclose(f); + } else + buf_appends(out, FROMDISCLAIMER); + } + +#if 0 + buf_append(out, in->data + in->ptr, in->length - in->ptr); +#endif /* 0 */ + while (buf_getline(in, line) != -1) { + if (boundary(line, mboundary)) { + buf_cat(out, line); + buf_nl(out); + while (buf_getline(in, line) == 0) { /* MIME body part header */ + err = doblock(line, filter, 1); + if (err == -1) + goto end; + buf_cat(out, line); + buf_nl(out); + } + } + if (BINFILTER && l > 20 && line->length == l && + (bufleft(line, "M") || !buffind(line, " "))) + inbinary++; + else + inbinary = 0, l = line->length; + if (bufileft(line, begin_pgp) || bufileft(line, begin_key)) + inpgp = 1; + if (bufileft(line, end_pgp) || bufileft(line, end_key)) + inpgp = 0; + if (inbinary < 10 || inpgp) { + buf_cat(out, line); + buf_nl(out); + } else if (inbinary == 10) { + errlog(NOTICE, "Binary message detected.\n"); + if (BINFILTER > 1) { + err = -1; + goto end; + } + buf_appends(out, BINDISCLAIMER); + buf_nl(out); + } + } + + f = mix_openfile(MSGFOOTERFILE, "r"); + if (f != NULL) { + buf_read(out, f); + fclose(f); + } else + buf_appends(out, MSGFOOTER); + + /* return 1 for user supplied From line */ + err = from; + if (dest == 0) + err = -1; + +end: + buf_move(in, out); + buf_free(out); + buf_free(line); + buf_free(line2); + if (block) buf_free(block); + buf_free(filter); + buf_free(mid); + buf_free(mboundary); + return (err); +} + +BUFFER *readdestblk( ) +{ + char *destblklst = (char *)malloc( strlen( DESTBLOCK )+1 ); + char *destblk = NULL; + FILE *f; + BUFFER *addresses; + BUFFER *temp; + int err = 1; + + addresses = buf_new( ); + temp = buf_new( ); + + strcpy( destblklst, DESTBLOCK ); + + while ( (destblk = strtok( destblk ? NULL : destblklst, " " )) ) + { + if ( (f = mix_openfile( destblk, "r" )) ) + { + if ( !buf_read( temp, f ) ) + { + buf_cat( addresses, temp ); + err = 0; + } + fclose( f ); + } + } + + free( destblklst ); + buf_free( temp ); + + if ( err ) { buf_free( addresses ); return NULL; } + else return addresses; +} + +int doblock(BUFFER *line, BUFFER *filter, int logandreset) +/* logandreset is usually 0 + * it is only set to 1 when called from doallow + * which only checks whether messages are allowed to + * be sent directly + */ +{ + int block = 0; + BUFFER *pattern, *result; + char *t; +#ifdef USE_PCRE + int errptr, match; + const char *error; + pcre *compiled; + int ovector[21]; + char *newstr; +#endif /* USE_PCRE */ + + pattern = buf_new(); + result = buf_new(); + assert(filter != NULL); + + buf_rewind(filter); + while (buf_getline(filter, pattern) != -1) + if (pattern->length > 0 && !bufleft(pattern, "#")) { + if (bufleft(pattern, "/") && (t = strchr(pattern->data + 1, '/')) + != NULL) { +#ifdef USE_PCRE + *t = '\0'; + compiled = pcre_compile(pattern->data + 1, PCRE_CASELESS, + &error, &errptr +#ifndef USE_PCRE_OLD + ,NULL +#endif /* not USE_PCRE_OLD */ + ); + if (compiled) { + match = pcre_exec(compiled, NULL, line->data, + line->length, +#if (PCRE_MAJOR == 2 && PCRE_MINOR >= 06) + 0, +#endif /* (PCRE_MAJOR == 2 && PCRE_MINOR >= 06) */ +#if (PCRE_MAJOR >= 3) + 0, +#endif /* (PCRE_MAJOR >= 3) */ + 0, ovector, sizeof(ovector) / sizeof(int)); + free(compiled); + + if (match < -1) { + *t = '/'; + errlog(ERRORMSG, "Bad regexp %b\n", pattern); + } + else if (match >= 0) { + /* "/pattern/q" kills the entire message */ + if (logandreset + && strlen(pattern->data + 1) + 1 < pattern->length + && pattern->data[pattern->length - 1] == 'q') { + *t = '/'; + errlog(NOTICE, + "Message rejected: %b matches %b.\n", line, pattern); + block = -1; + break; + } + if (strlen(pattern->data + 1) + 1 < pattern->length + && pattern->data[pattern->length - 1] == '/') { + pattern->data[pattern->length - 1] = '\0'; + newstr = pattern->data + strlen(pattern->data) + 1; + buf_reset(result); + buf_append(result, line->data, ovector[0]); + while (strchr(newstr, '$')) { + strchr(newstr, '$')[0] = '\0'; + buf_appends(result, newstr); + newstr += strlen(newstr) + 1; + if (*newstr >= '1' && *newstr <= '9') + buf_append(result, line->data + + ovector[2 * (*newstr - '0')], + ovector[2 * (*newstr - '0') + 1] - + ovector[2 * (*newstr - '0')]); + newstr++; + } + buf_appends(result, newstr); + buf_appends(result, line->data + ovector[1]); + buf_clear(line); + buf_appends(line, result->data); + } else { + block = 1; + *t = '/'; + if (logandreset) + errlog(NOTICE, "Blocked header line: %b matches %b.\n", + line, pattern); + } + } + } else { + *t = '/'; + errlog(ERRORMSG, "Bad regexp %b\n", pattern); + } +#else /* end of USE_PCRE */ + errlog(ERRORMSG, "No regexp support! Ignoring %b\n", pattern); +#endif /* else if not USE_PCRE */ + } else if (bufifind(line, pattern->data)) { + if (logandreset ) + errlog(NOTICE, "Blocked header line: %b matches %b.\n", + line, pattern); + block = 1; + } + } + + if (logandreset && (block == 1)) + buf_reset(line); + + buf_free(pattern); + buf_free(result); + return (block); +} + +int mix_armor(BUFFER *in) +{ + BUFFER *out, *md; + + md = buf_new(); + out = buf_new(); + + if (in->length != 20480) + return (-1); + + buf_sets(out, "\n::\n"); + buf_appends(out, remailer_type); + buf_appends(out, VERSION); + buf_nl(out); + buf_nl(out); + buf_appends(out, begin_remailer); + buf_nl(out); + buf_appends(out, "20480\n"); + digest_md5(in, md); + encode(md, 0); + buf_cat(out, md); + buf_nl(out); + encode(in, 40); + buf_cat(out, in); + buf_appends(out, end_remailer); + buf_nl(out); + + buf_move(in, out); + buf_free(out); + buf_free(md); + return (0); +} diff --git a/Src/random.c b/Src/random.c @@ -0,0 +1,210 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Randomness + $Id: random.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include "crypto.h" +#include <fcntl.h> +#ifdef POSIX +#include <sys/time.h> +#include <unistd.h> +#else /* end of POSIX */ +#include <io.h> +#include <process.h> +#endif /* else if not POSIX */ +#ifdef WIN32 +#include <windows.h> +#endif /* WIN32 */ +#include <assert.h> +#include <string.h> + +int rnd_state = RND_NOTSEEDED; + +#ifdef USE_OPENSSL +int rnd_init(void) +{ + char r[PATHMAX]; + int n; + LOCK *rndlock; + + if (rnd_state == RND_SEEDED) + return(0); + rndlock = lockfile(MIXRAND); + mixfile(r, MIXRAND); + n = RAND_load_file(r, 1024); + if (n < 256 && rnd_seed() == -1) + goto err; + rnd_time(); + RAND_write_file(r); + rnd_state = RND_SEEDED; + err: + unlockfile(rndlock); + return (rnd_state == RND_SEEDED ? 0 : -1); +} + +int rnd_final(void) +{ + int err = 0; + char r[PATHMAX]; + LOCK *rndlock; + + if (rnd_state != RND_SEEDED) + return(-1); + + rnd_update(NULL, 0); + rndlock = lockfile(MIXRAND); + mixfile(r, MIXRAND); + RAND_load_file(r, 1024); /* add seed file again in case other instances + of the program have used it */ + if (RAND_write_file(r) < 1) + err = -1; + unlockfile(rndlock); + RAND_cleanup(); + return (err); +} + +int rnd_add(byte *b, int l) +{ + RAND_seed(b, l); + return (0); +} +#endif /* USE_OPENSSL */ + +void rnd_time(void) +{ + int pid; + +#ifdef WIN32 + SYSTEMTIME t; +#endif /* WIN32 */ + +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + + gettimeofday(&tv, 0); + rnd_add((byte *) &tv, sizeof(tv)); +#elif defined(WIN32) /* end of HAVE_GETTIMEOFDAY */ + GetSystemTime(&t); + rnd_add((byte *) &t, sizeof(t)); +#else /* end of defined(WIN32) */ + rnd_add((byte *) time(NULL), sizeof(time_t)); +#endif /* else if not defined(WIN32), HAVE_GETTIMEOFDAY */ + pid = getpid(); + rnd_add((byte *) &pid, sizeof(pid)); +} + +void rnd_update(byte *seed, int l) +{ + int fd = -1; + byte b[512]; + + rnd_time(); + if (seed) + rnd_add(seed, l); +#ifdef DEV_URANDOM + fd = open(DEV_URANDOM, O_RDONLY); + if (fd != -1) { + ssize_t ret; + + ret = read(fd, b, sizeof(b)); + if (ret > 0) { + rnd_add(b, ret); + } + close(fd); + } +#endif /* DEV_URANDOM */ +} + +int rnd_bytes(byte *b, int n) +{ + /* we frequently need to get small amounts of random data. + speed up by pre-generating dating data */ + + static byte rand[BUFSIZE]; + static int idx = BUFSIZE; + + if (rnd_state != RND_SEEDED) + rnd_error(); + + if (n + idx < BUFSIZE) { + memcpy(b, rand + idx, n); + idx += n; + } else + RAND_bytes(b, n); + + if (idx + 256 > BUFSIZE) { + RAND_bytes(rand, BUFSIZE); + idx = 0; + } + return (0); +} + +int rnd_number(int n) +{ + int r; + + assert(n > 0); + if (n > 65535) + do + r = rnd_byte() * 65536 + + rnd_byte() * 256 + rnd_byte(); + while (r >= n); + else if (n > 255) + do + r = rnd_byte() * 256 + rnd_byte(); + while (r >= n); + else + do + r = rnd_byte(); + while (r >= n); + return r; +} + +byte rnd_byte() +{ + byte b; + + rnd_bytes(&b, 1); + return b; +} + +void rnd_initialized(void) +{ + rnd_state = RND_SEEDED; +} + +#ifdef WIN32 + +#define NEEDED 256 + +int rnd_mouse(UINT i, WPARAM w, LPARAM l) +{ + static int entropy = 0; + static int x, y, dx, dy; + int newx, newy, newdx, newdy; + int rnd[4]; + + if (i == WM_MOUSEMOVE) { + newx = LOWORD(l); + newy = HIWORD(l); + newdx = x - newx; + newdy = y - newy; + if (dx != 0 && dy != 0 && dx - newdx != 0 && dy - newdy != 0) { + entropy++; + if (entropy >= NEEDED) + rnd_state = RND_SEEDED; + } + x = newx, y = newy, dx = newdx, dy = newdy; + rnd[0] = x; rnd[1] = y; rnd[2] = dx; rnd[3] = dy; + rnd_update((byte*)rnd, 4 * sizeof(int)); + } + return (rnd_state == RND_SEEDED ? 100 : entropy * 100 / NEEDED); +} +#endif /* WIN32 */ diff --git a/Src/rem.c b/Src/rem.c @@ -0,0 +1,709 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Process remailer messages + $Id: rem.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef POSIX +#include <unistd.h> +#else /* end of POSIX */ +#include <io.h> +#endif /* else if not POSIX */ +#ifndef _MSC +#include <dirent.h> +#endif /* not _MSC */ +#include <assert.h> + +int blockrequest(BUFFER *message); +int create_dummy_mailin(); + +#define REQUESTHELP 100 +#define REQUESTSTATS 101 +#define REQUESTKEY 200 +#define REQUESTCONF 201 +#define REQUESTOPKEY 202 +#define REQUESTOTHER 203 +#define BLOCKREQUEST 666 +#define DISABLED 99 + +#define CPUNKMSG 1 +#define MIXMSG 2 + + +/** \brief get replies for additional information requests + * + * \param reply The buffer to store the reply in + * \param file The file or name of information a user requested + * \returns 0 on success; -1 if a ressource has a valid name + * but doesn't exist; 1 if the ressource name isn't valid. + * + * This function returns additional information that a + * user may have requested. One obvious example is help files + * in different languages. We don't want to hack the source every + * time we or somebody else adds a new language. + * + * Therefore we add a new directory where the operator may + * just create new files (say "remailer-help-de"). If a user + * requests that using this (file|ressource) name in the + * subject line we respond by sending it. + * + * Perhaps we should build something that returns an index of + * available files (FIXME if done). + * + * A ressource name needs to start with the string "remailer-" + * and must only consist of alphanumerical characters and dashes. + * Checking is done by this function and an error returned + * if this is violated. + */ +int get_otherrequests_reply(BUFFER *reply, BUFFER *filename) +{ + FILE *f = NULL; + int c; + int err; + BUFFER *path; + + path = buf_new(); + + assert(filename); + assert(reply); + + buf_rewind(filename); + err = bufileft(filename, "remailer-"); + if (! err) { + err = 1; + goto end; + }; + + while ((c = buf_getc(filename)) != -1) { + int ok = (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '-'; + if (!ok) { + err = 1; + goto end; + }; + }; + buf_rewind(filename); + + buf_appends(path, REQUESTDIR); + buf_appends(path, "/"); + buf_cat(path, filename); + + f = mix_openfile(path->data, "r"); + if (f == NULL) { + err = -1; + goto end; + }; + + buf_read(reply, f); + err = 0; +end: + if (f) + fclose(f); + buf_free(path); + return (err); +} + +int mix_decrypt(BUFFER *message) +{ + int type = 0; + BUFFER *field, *content; + BUFFER *to, *subject, *replyto, *reply; + BUFFER *otherrequest; + FILE *f; + BUFFER *block; + int err = 0; + int quoted_printable = 0; /* is this message quoted printable encoded */ + + mix_init(NULL); + field = buf_new(); + content = buf_new(); + to = buf_new(); + replyto = buf_new(); + reply = buf_new(); + block = buf_new(); + subject = buf_new(); + otherrequest = buf_new(); + buf_sets(subject, "Subject: Re: your mail"); + + buf_rewind(message); + + f = mix_openfile(SOURCEBLOCK, "r"); + if (f != NULL) { + buf_read(block, f); + fclose(f); + } + for (;;) { + err = buf_getheader(message, field, content); + if (err == 1) { + /* "::" marks for additional header lines */ + while (buf_lookahead(message, field) == 1) + buf_getheader(message, field, content); + if (isline(field, HDRMARK)) + continue; + else + goto hdrend; + } + if (err == -1) + goto hdrend; + + if ((bufieq(field, "from") || bufieq(field, "sender") || bufieq(field,"received")) && + doblock(content, block, 1) != 0) + goto end; + + if (bufieq(field, "to")) + buf_cat(to, content); + else if (bufieq(field, "from") && replyto->length == 0) + /* reply to From address if no Reply-To header present */ + buf_set(replyto, content); + else if (bufieq(field, "reply-to")) + buf_set(replyto, content); + else if (MIX && bufieq(field, "remailer-type") && + bufileft(content, "mixmaster")) + type = MIXMSG; + else if (bufieq(field, "subject")) { + if (bufieq(content, "help") || bufieq(content, "remailer-help")) + type = REQUESTHELP; + else if (bufieq(content, "remailer-stats")) + type = REQUESTSTATS; + else if (bufieq(content, "remailer-key")) + type = REQUESTKEY; + else if (bufieq(content, "remailer-adminkey")) + type = REQUESTOPKEY; + else if (bufieq(content, "remailer-conf")) + type = REQUESTCONF; + else if (bufileft(content, "remailer-")) { + type = REQUESTOTHER; + buf_set(otherrequest, content); + } else if (bufileft(content, "destination-block")) + type = BLOCKREQUEST; + else { + buf_sets(subject, "Subject: "); + if (!bufileft(content, "re:")) + buf_appends(subject, "Re: "); + buf_cat(subject, content); + } + } else if (bufieq(field, "test-to") || bufieq(field, "encrypted") || + bufieq(field, "anon-to") || + bufieq(field, "request-remailing-to") || + bufieq(field, "remail-to") || bufieq(field, "anon-post-to") || + bufieq(field, "post-to") || bufieq(field, "anon-send-to") || + bufieq(field, "send-to") || bufieq(field, "remix-to") || + bufieq(field, "encrypt-to")) + type = CPUNKMSG; + else if (bufieq(field, "content-transfer-encoding") + && bufieq(content, "quoted-printable")) { + quoted_printable = 1; + } + + } +hdrend: + if (quoted_printable) + qp_decode_message(message); + + if (type > 0 && REMAIL == 0) + type = DISABLED; + switch (type) { + case REQUESTHELP: + if (sendinfofile(HELPFILE, NULL, replyto, NULL) == -1) + errlog(WARNING, "No help file available.\n"); + break; + case REQUESTKEY: + err = key(reply); + if (err == 0) + err = sendmail(reply, REMAILERNAME, replyto); + break; + case REQUESTOPKEY: + err = adminkey(reply); + if (err == 0) + err = sendmail(reply, REMAILERNAME, replyto); + break; + case REQUESTSTATS: + err = stats(reply); + if (err == 0) + err = sendmail(reply, REMAILERNAME, replyto); + break; + case REQUESTCONF: + err = conf(reply); + if (err == 0) + err = sendmail(reply, REMAILERNAME, replyto); + break; + case REQUESTOTHER: + err = get_otherrequests_reply(reply, otherrequest); + if (err == 0) + err = sendmail(reply, REMAILERNAME, replyto); + break; + case CPUNKMSG: + err = t1_decrypt(message); + if (err != 0) { + errlog(LOG, "Invalid type 1 message from %b\n", replyto); + sendinfofile(USAGEFILE, USAGELOG, replyto, NULL); + logmail(err == -2 ? MAILUSAGE : MAILERROR, message); + } else + create_dummy_mailin(); + break; + case MIXMSG: + err = t2_decrypt(message); + if (err == -1) { + errlog(LOG, "Invalid type 2 message from %b\n", replyto); + sendinfofile(USAGEFILE, USAGELOG, replyto, NULL); + logmail(MAILERROR, message); + } else + create_dummy_mailin(); + break; + case BLOCKREQUEST: + blockrequest(message); + /* Already wrote a log entry in blockrequest() */ + logmail(MAILBLOCK, message); + break; + case DISABLED: + errlog(ERRORMSG, "Remailer is disabled.\n"); + buf_sets(reply, "Subject: remailer error\n\nThe remailer is disabled.\n"); + sendmail(reply, REMAILERNAME, replyto); + logmail(MAILERROR, message); + break; + default: + if (strifind + (replyto->data, "mailer-daemon")) { + errlog(LOG, "Bounce mail from %b\n", replyto); + logmail(MAILBOUNCE, message); + } else if (bufifind(to, REMAILERADDR) && blockrequest(message)) { + /* Already wrote a log entry in blockrequest() */ + logmail(MAILBLOCK, message); + } else if (bufifind(to, REMAILERADDR)) { + errlog(LOG, "Non-remailer message from %b\n", replyto); + if (AUTOREPLY) + sendinfofile(USAGEFILE, USAGELOG, replyto, NULL); + logmail(MAILUSAGE, message); + } else if (bufifind(to, COMPLAINTS)) { + errlog(WARNING, "Abuse complaint from %b\n", replyto); + if (AUTOREPLY) + sendinfofile(ABUSEFILE, NULL, replyto, subject); + logmail(MAILABUSE, message); + } else if (ANONADDR[0] && bufifind(to, ANONADDR)) { + errlog(LOG, "Reply to anonymous message from %b\n", replyto); + if (AUTOREPLY) + sendinfofile(REPLYFILE, NULL, replyto, subject); + logmail(MAILANON, message); + } else { + errlog(DEBUGINFO, "Mail from %b\n", replyto); + logmail(MAILBOX, message); + } + err = 1; + } +end: + buf_free(field); + buf_free(content); + buf_free(to); + buf_free(replyto); + buf_free(reply); + buf_free(block); + buf_free(subject); + buf_free(otherrequest); + return (err); +} + +int create_dummy_mailin() +{ + while (rnd_number(100) < INDUMMYP) { + errlog(DEBUGINFO, "Generating dummy message with incoming mail.\n"); + if (mix_encrypt(MSG_NULL, NULL, NULL, 1, NULL) == -1) + return -1; + } + return 0; +} + +int t2_decrypt(BUFFER *in) +{ + int err = 0; + BUFFER *msg; + + msg = buf_new(); + do { + err = mix_dearmor(in, msg); + if (err != -1) { + err = mix2_decrypt(msg); + } + } + while (in->ptr + 1000 < in->length); /* accept several packets in one message */ + + buf_free(msg); + return (err); +} + +int mix_pool(BUFFER *msg, int type, long latent) +{ + char path[PATHMAX], pathtmp[PATHMAX]; + FILE *f; + int err = -1; + + f = pool_new(latent > 0 ? "lat" : "msg", pathtmp, path); + if (f != NULL) { + if (latent > 0) + fprintf(f, "%d %ld\n", type, latent + time(NULL)); + else + fprintf(f, "%d 0\n", type); + err = buf_write_sync(msg, f); + } + if (err == 0) { + rename(pathtmp, path); + errlog(DEBUGINFO, "Added message to pool.\n"); + } + return (err); +} + +int pool_packetfile(char *fname, BUFFER *mid, int packetnum) + /* create a filename */ +{ +#ifdef SHORTNAMES + sprintf(fname, "%s%cp%02x%02x%02x%01x.%02x", POOLDIR, DIRSEP, + mid->data[0], mid->data[1], mid->data[2], mid->data[3] & 15, + packetnum); +#else /* end of SHORTNAMES */ + sprintf(fname, "%s%cp%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP, + packetnum, mid->data[0], mid->data[1], mid->data[2], mid->data[3], + mid->data[4], mid->data[5] & 15); +#endif /* else if not SHORTNAMES */ + return (0); +} + +void pool_packetexp(void) +{ + char *path; + DIR *d; + struct dirent *e; + struct stat sb; + + d = opendir(POOLDIR); + errlog(DEBUGINFO, "Checking for old parts.\n"); + if (d != NULL) + for (;;) { + e = readdir(d); + if (e == NULL) + break; + if (e->d_name[0] == 'p' || e->d_name[0] == 'e' || e->d_name[0] == 't') { + path=malloc(strlen(POOLDIR)+strlen(e->d_name)+strlen(DIRSEPSTR)+1); + if (path) { + strcpy(path, POOLDIR); + strcat(path, DIRSEPSTR); + strcat(path, e->d_name); + if (stat(path, &sb) == 0 && time(NULL) - sb.st_mtime > PACKETEXP) { + if (e->d_name[0] == 'p') { + errlog(NOTICE, "Expiring incomplete partial message %s.\n", + e->d_name); + } + else if (e->d_name[0] == 'e') { + errlog(NOTICE, "Expiring old error message %s.\n", + e->d_name); + } + else if (e->d_name[0] == 't') { + errlog(NOTICE, "Expiring moldy temporary message %s.\n", + e->d_name); + } + unlink(path); + } + free(path); + } + } + } + closedir(d); +} + +void logmail(char *mailbox, BUFFER *message) +{ + time_t t; + struct tm *tc; + char line[LINELEN]; + + /* mailbox is "|program", "user@host", "stdout", "Maildir/" or "filename" */ + buf_rewind(message); + if (mailbox[0] == '\0') /* default action */ + mailbox = MAILBOX; + if (strieq(mailbox, "stdout")) + buf_write(message, stdout); + else if (mailbox[0] == '|') { + FILE *p; + + errlog(DEBUGINFO, "Piping message to %s.\n", mailbox + 1); + p = openpipe(mailbox + 1); + if (p != NULL) { + buf_write(message, p); + closepipe(p); + } + } else if (strchr(mailbox, '@')) { + BUFFER *field, *content; + + field = buf_new(); + content = buf_new(); + while (buf_getheader(message, field, content) == 0) + if (bufieq(field, "x-loop") && bufifind(content, REMAILERADDR)) { + errlog(WARNING, "Loop detected! Message not sent to %s.\n", mailbox); + goto isloop; + } + buf_sets(content, mailbox); + sendmail_loop(message, NULL, content); + isloop: + buf_free(field); + buf_free(content); + } else if (mailbox[strlen(mailbox)-1] == DIRSEP) { + /* the user is requesting Maildir delivery */ + if(maildirWrite(mailbox, message, 1) != 0) { + errlog(ERRORMSG, "Can't write to maildir %s\n", mailbox); + return; + } + } else { + FILE *mbox; + + mbox = mix_openfile(mailbox, "a"); + if (mbox == NULL) { + errlog(ERRORMSG, "Can't write to mail folder %s\n", mailbox); + return; + } + lock(mbox); + if (!bufileft(message, "From ")) { + t = time(NULL); + tc = localtime(&t); + strftime(line, LINELEN, "From Mixmaster %a %b %d %H:%M:%S %Y\n", tc); + fprintf(mbox, line); + } + buf_write(message, mbox); + fprintf(mbox, "\n\n"); + unlock(mbox); + fclose(mbox); + } +} + +int blockrequest(BUFFER *message) +{ + int request = 0, num, i; + BUFFER *from, *line, *field, *content, *addr, *remailer_addr, *copy_addr; + REMAILER remailer[MAXREM]; + FILE *f; + char *destblklst = (char *)malloc( strlen(DESTBLOCK)+1 ); + char *destblk; + + from = buf_new(); + line = buf_new(); + field = buf_new(); + content = buf_new(); + addr = buf_new(); + remailer_addr = buf_new(); + copy_addr = buf_new(); + + if (destblklst == NULL) { + errlog(ERRORMSG, "Can't malloc %n bytes for destblklst.\n", strlen(DESTBLOCK)+1); + goto end; + }; + + buf_rewind(message); + while (buf_getheader(message, field, content) == 0) + if (bufieq(field, "from")) + buf_set(from, content); + else if (bufieq(field, "subject")) + buf_cat(message, content); + /* Append the subject to the message body so destination block requests + in the subject line work too (we process the body a few lines down) */ + while (buf_getline(message, line) != -1) + if (bufifind(line, "destination-block")) { + buf_clear(addr); + request = 1; + { + int c = 0; + + while (!strileft(line->data + line->ptr, "block")) + line->ptr++; + while (c != ' ' && c != -1) + c = tolower(buf_getc(line)); + while (c == ' ') + c = buf_getc(line); + if (c != -1) + do { + buf_appendc(addr, c); + c = buf_getc(line); + } while (c > ' '); + } + if (addr->length == 0) { + rfc822_addr (from, addr); + buf_chop(addr); + } + /* Check whether somebody wants us to block ourselves */ + buf_set(copy_addr, addr); + buf_sets(remailer_addr, REMAILERADDR); + if (doblock(remailer_addr, copy_addr, 1)) { + errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from); + request = 2; + goto end; + } + /* Check if some evil person tries to block a known type II remailer */ + num = mix2_rlist(remailer, NULL); + for (i = 0; i < num; i++) { + buf_sets(remailer_addr, remailer[i].addr); + if (doblock(remailer_addr, copy_addr, 1)) { + errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from); + request = 2; + goto end; + } + } + /* Check if some evil person tries to block a known type I remailer */ + num = t1_rlist(remailer, NULL); + for (i = 0; i < num; i++) { + buf_sets(remailer_addr, remailer[i].addr); + if (doblock(remailer_addr, copy_addr, 1)) { + errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from); + request = 2; + goto end; + } + } + + if (buf_ieq(addr, from)) + errlog(NOTICE, "Blocking request for %b\n", addr); + else + errlog(NOTICE, "Blocking request for %b from %b\n", addr, from); + if (AUTOBLOCK) { + buf_clear(line); + rfc822_addr(addr, line); + if (line->length == 0) { + errlog(LOG, "Nothing to block after rfc822_addr().\n"); + } else + if (bufleft(line, "/")) { + errlog(LOG, "Ignoring blocking request: %b is a regex.\n", addr); + } else { + if (strchr(line->data, '@') && strchr(strchr(line->data, '@'), '.')) { + strcpy( destblklst, DESTBLOCK ); + destblk = strtok( destblklst, " " ); + f = mix_openfile( destblk, "a" ); + if (f != NULL) { + lock(f); + + buf_chop(line); + sendinfofile(BLOCKFILE, NULL, line, NULL); + if (line->length) { + fprintf(f, "%s\n", line->data); + } else + errlog(NOTICE, "%b already blocked.\n", addr); + unlock(f); + fclose(f); + } else + errlog(ERRORMSG, "Can't write to %s.\n", DESTBLOCK); + } else + errlog(WARNING, "Invalid address not added to %s: %b\n", DESTBLOCK, + addr); + } + } + } + +end: + free( destblklst ); + buf_free(from); + buf_free(line); + buf_free(field); + buf_free(content); + buf_free(addr); + buf_free(remailer_addr); + buf_free(copy_addr); + + return (request); +} + + +int idexp(void) +{ + FILE *f; + long now, then; + LOCK *i; + idlog_t idbuf; + long fpi = sizeof(idlog_t), fpo = sizeof(idlog_t); + + if (IDEXP == 0) + return (0); + + f = mix_openfile(IDLOG, "rb+"); + if (f == NULL) + return (-1); + i = lockfile(IDLOG); + now = time(NULL); + if (fread(&idbuf, 1, sizeof(idlog_t), f) != sizeof(idlog_t)) { /* replace first line */ + fclose(f); + unlockfile(i); + return (-1); + } + then = idbuf.time; + memset(idbuf.id,0,sizeof(idbuf.id)); + idbuf.time = now - IDEXP; + fseek(f,0,SEEK_SET); + fwrite(&idbuf,1,sizeof(idlog_t),f); + fseek(f,fpi,SEEK_SET); /* this fseek does nothing, but MSVC CRT happilly reads past EOF (!!!) if we do not fseek here :-/ */ + while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) { + fpi+=sizeof(idlog_t); + then = idbuf.time; + if (now - then < IDEXP && + now - then > - SECONDSPERDAY * 180 ) + /* also expire packets that are dated more than half a year in the future. + * That way we get rid of invalid packets introduced by the switch to a + * binary id.log. */ + { + fseek(f,fpo,SEEK_SET); + fwrite(&idbuf,1,sizeof(idlog_t),f); + fpo += sizeof(idlog_t); + fseek(f,fpi,SEEK_SET); + } + } +#ifdef _MSC + chsize(fileno(f),fpo); +#else /* end of _MSC */ + ftruncate(fileno(f),fpo); +#endif /* else if not _MSC */ + fclose(f); + unlockfile(i); + return (0); +} + + +int pgpmaxexp(void) +{ + FILE *f; + BUFFER *b; + long now, then; + LOCK *i; + char temp[LINELEN]; + + f = mix_openfile(PGPMAXCOUNT, "rb+"); + if (f == NULL) + return (-1); + i = lockfile(PGPMAXCOUNT); + b = buf_new(); + now = time(NULL); + + while (fgets(temp, sizeof(temp), f) != NULL) + if (sscanf(temp, "%ld", &then) && + then >= now - SECONDSPERDAY) + buf_appends(b, temp); + + fseek(f,0,SEEK_SET); + + buf_write(b, f); + +#ifdef _MSC + chsize(fileno(f),b->length); +#else /* end of _MSC */ + ftruncate(fileno(f),b->length); +#endif /* else if not _MSC */ + + fclose(f); + unlockfile(i); + buf_free(b); + return (0); +} diff --git a/Src/rem1.c b/Src/rem1.c @@ -0,0 +1,599 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Process Cypherpunk remailer messages + $Id: rem1.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <ctype.h> +#include <time.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +static int t1msg(BUFFER *in, int hdr); + +int isline(BUFFER *line, char *text) +{ + int i; + + if (!bufileft(line, text)) + return (0); + + for (i = strlen(text); i < line->length; i++) + if (!isspace(line->data[i])) + return(0); + return(1); +} + +int t1_decrypt(BUFFER *in) +{ + int ret; + + buf_rewind(in); + if (TYPE1[0] == '\0') + ret = t1msg(in, 1); + else { + FILE *f; + + f = openpipe(TYPE1); + if (f == NULL) + return -1; + buf_write(in, f); + ret = closepipe(f); + } + if (ret == 0) + stats_log(1); + return (ret); +} + +#ifdef USE_IDEA +void t1_esub(BUFFER *esub, BUFFER *subject) +{ + BUFFER *iv, *out; + char hex[33]; + + iv = buf_new(); + out = buf_new(); + + buf_appendrnd(iv, 8); + id_encode(iv->data, hex); + buf_append(out, hex, 16); + + digest_md5(esub, esub); + digest_md5(subject, subject); + buf_ideacrypt(subject, esub, iv, ENCRYPT); + id_encode(subject->data, hex); + buf_appends(out, hex); + buf_move(subject, out); + buf_free(iv); + buf_free(out); +} +#endif /* USE_IDEA */ + +#define N(X) (isdigit(X) ? (X)-'0' : 0) + +static int readnum(BUFFER *b, int f) +{ + int num = 0; + + if (b->length > 0) + sscanf(b->data, "%d", &num); + num *= f; + if (strchr(b->data, 'r')) + num = rnd_number(num) + 1; + return (num); +} + +static int readdate(BUFFER *b) +{ + int num = -1; + + if (b->length > 0) + num = parsedate(b->data); + return (num); +} + +static int reached_maxcount(BUFFER *md, int maxcount) +{ + FILE *f; + char temp[LINELEN]; + int count = 0; + int err = 0; + long then; + time_t now = time(NULL); + + assert(md->length > 0); + + encode(md, 0); + + f = mix_openfile(PGPMAXCOUNT, "a+"); /* create file if it does not exist */ + fseek(f,0,SEEK_SET); + if (f == NULL) { + errlog(ERRORMSG, "Can't open %s!\n", PGPMAXCOUNT); + return (-1); + } + lock(f); + while (fgets(temp, sizeof(temp), f) != NULL) + if (sscanf(temp, "%ld", &then) && + (then >= now - SECONDSPERDAY) && + strstr (temp, md->data)) + count++; + + if (count > maxcount) + err = 1; + else + fprintf(f, "%ld %s\n", (long) time(NULL), md->data); + + unlock(f); + fclose(f); + return (err); +} + +static int t1msg(BUFFER *in, int hdr) + /* hdr = 1: mail header, hdr = 2: pasted header, hdr = 0: ignore */ +{ + BUFFER *field, *content, *line; + BUFFER *cutmarks, *to, *newsgroups, *ek, *ekdes, *ekcast, *esub, *subject; + BUFFER *temp, *header, *out; + BUFFER *test, *testto, *remixto; + BUFFER *digest; + int err = 0; + int encrypted = 0; + int type = -1; + int latent = 0; + int remix = 0, repgp = 0; + int inflate = 0; + int maxsize = -1; + int maxcount = -1; + int maxdate = -2; /* -2 not used, -1 parse error */ + + field = buf_new(); + content = buf_new(); + line = buf_new(); + to = buf_new(); + remixto = buf_new(); + cutmarks = buf_new(); + newsgroups = buf_new(); + ek = buf_new(); + ekdes = buf_new(); + ekcast = buf_new(); + esub = buf_new(); + subject = buf_new(); + temp = buf_new(); + header = buf_new(); + out = buf_new(); + test = buf_new(); + testto = buf_new(); + digest = buf_new(); + + if (REMIX == 1) + remix = 2; + if (!UNENCRYPTED) + encrypted = -1; + +header: + while (buf_getheader(in, field, content) == 0) { + if (header->length == 0 && bufieq(content, ":")) /* HDRMARK */ + hdr = 2; + + if (bufieq(field, "test-to")) + buf_set(testto, content); + else if (PGP && bufieq(field, "encrypted")) + encrypted = 1; + else if (bufieq(field, "remix-to")) { + remix = 1; repgp = 0; + buf_set(remixto, content); + if (type == -1) + type = MSG_MAIL; + } else if (bufieq(field, "encrypt-to")) { + repgp = remix = 1; + buf_set(remixto, content); + if (type == -1) + type = MSG_MAIL; + } else if (bufieq(field, "anon-to") || + bufieq(field, "request-remailing-to") || + bufieq(field, "remail-to") || + bufieq(field, "anon-send-to")) { + if (bufieq(field, "remail-to")) + repgp = remix = 0; + if (to->length > 0) + buf_appendc(to, ','); + buf_cat(to, content); + if (type == -1) + type = MSG_MAIL; + } else if (bufieq(field, "anon-post-to") || bufieq(field, "post-to")) { + if (newsgroups->length > 0) + buf_appendc(newsgroups, ','); + buf_cat(newsgroups, content); + type = MSG_POST; + } else if (bufieq(field, "cutmarks")) + buf_set(cutmarks, content); + else if (bufieq(field, "latent-time")) { + byte *q; + int l; + + q = content->data; + l = strlen(q); + latent = 0; + if (q[0] == '+') + q++; + if (l >= 5 && q[2] == ':') + latent = 600 * N(q[0]) + 60 * N(q[1]) + 10 * N(q[3]) + N(q[4]); + else if (l >= 4 && q[1] == ':') + latent = 60 * N(q[0]) + 10 * N(q[2]) + N(q[3]); + else if (l >= 3 && q[0] == ':') + latent = 10 * N(q[1]) + N(q[2]); + if (!bufleft(content, "+")) { + time_t now; + + time(&now); + latent -= localtime(&now)->tm_hour * 60; + if (latent < 0) + latent += 24 * 60; + } + if (q[l - 1] == 'r') + latent = rnd_number(latent); + } else if (bufieq(field, "null")) + type = MSG_NULL; +#ifdef USE_IDEA + else if (bufieq(field, "encrypt-key") || bufieq(field, "encrypt-idea")) + buf_set(ek, content); +#else + else if (bufieq(field, "encrypt-key") || bufieq(field, "encrypt-idea")) + buf_set(ekdes, content); +#endif + else if (bufieq(field, "encrypt-des") || bufieq(field, "encrypt-3des")) + buf_set(ekdes, content); + else if (bufieq(field, "encrypt-cast") || bufieq(field, "encrypt-cast5")) + buf_set(ekcast, content); + else if (bufieq(field, "encrypt-subject")) + buf_set(esub, content); + else if (bufieq(field, "inflate")) { + inflate = readnum(content, 1024); + if (inflate > INFLATEMAX * 1024) + inflate = INFLATEMAX * 1024; + } else if (bufieq(field, "rand-hop")) { + int randhops, i; + randhops = readnum(content, 1); + if (randhops > MAXRANDHOPS) + randhops = MAXRANDHOPS; + buf_clear(temp); + if (remixto->length) + buf_move(temp, remixto); + for (i = 0; i < randhops; i++) { + if (remixto->length > 0) + buf_appendc(remixto, ','); + buf_appendc(remixto, '*'); + } + if (temp->length) { + buf_appendc(remixto, ','); + buf_cat(remixto, temp); + } + } else if (bufieq(field, "max-size") || bufieq(field, "maxsize")) + maxsize = readnum(content, 1024); + else if (bufieq(field, "max-count") || bufieq(field, "maxcount")) + maxcount = readnum(content, 1); + else if (bufieq(field, "max-date") || bufieq(field, "maxdate")) + maxdate = readdate(content); +#if USE_NSUB + else if (bufieq(field, "subject")) + buf_set(subject, content); +#endif /* USE_NSUB */ + } + + if (cutmarks->length > 0) { + BUFFER *cut; + + cut = buf_new(); + buf_clear(temp); + + while ((err = buf_getline(in, line)) != -1 && !buf_eq(line, cutmarks)) { + buf_cat(temp, line); + buf_nl(temp); + } + while (err != -1) { + err = buf_getline(in, line); + if (err == -1 || buf_eq(line, cutmarks)) { + t1msg(cut, 0); + buf_clear(cut); + } else { + buf_cat(cut, line); + buf_nl(cut); + } + } + buf_move(in, temp); + buf_clear(cutmarks); + } + if (encrypted == 1) { +#ifdef USE_PGP + err = pgp_dearmor(in, temp); + if (err == 0) { + BUFFER *pass; + digest_sha1(temp, digest); + + pass = buf_new(); + buf_sets(pass, PASSPHRASE); + err = pgp_decrypt(temp, pass, NULL, NULL, NULL); + buf_free(pass); + } + if (err != -1 && temp->length == 0) { + errlog(ERRORMSG, "Empty PGP message.\n"); + err = -1; + goto end; + } + if (err != -1) { + buf_rest(temp, in); /* dangerous, but required for reply blocks */ + buf_move(in, temp); + encrypted = 0; + hdr = 0; + goto header; + } +#endif /* USE_PGP */ + if (testto->length == 0) + errlog(ERRORMSG, "Can't decrypt PGP message.\n"); + buf_appends(test, "Can't decrypt PGP message.\n"); + } + while ((err = buf_lookahead(in, line)) == 1) + buf_getline(in, line); +#if 0 + if (err == -1) + goto end; +#endif /* 0 */ + + if (isline(line, HDRMARK) && (hdr == 0 || hdr == 1)) { + buf_getline(in, NULL); + hdr = 2; + goto header; + } else if (isline(line, HASHMARK)) { + buf_getline(in, NULL); + for (;;) { + if (buf_lookahead(in, line) == 0 && bufileft(line, "subject:")) { + buf_getheader(in, field, content); + buf_set(subject, content); + } + if (buf_getline(in, line) != 0) + break; + buf_cat(header, line); + buf_nl(header); + } + } + if (encrypted == -1) { + if (testto->length == 0) + errlog(LOG, "Unencrypted message detected.\n"); + buf_appends(test, "Unencrypted message detected.\n"); + err = -2; + goto end; + } + if (maxdate == -1) { + if (testto->length == 0) + errlog(LOG, "Could not parse Max-Date: header.\n"); + buf_appends(test, "Could not parse Max-Date: header.\n"); + err = -2; + goto end; + } else if (maxdate >= 0 && maxdate <= time(NULL)) { + if (testto->length == 0) + errlog(LOG, "Message is expired.\n"); + buf_appends(test, "Message is expired.\n"); + err = -2; + goto end; + } + if (maxsize >= 0 && in->length >= maxsize) { + if (testto->length == 0) + errlog(LOG, "Message Size exceeds Max-Size.\n"); + buf_appends(test, "Message Size exceeds Max-Size.\n"); + err = -2; + goto end; + } + if (maxcount >= 0) { + if (digest->length == 0) { + if (testto->length == 0) + errlog(LOG, "Max-Count yet not encrypted.\n"); + buf_appends(test, "Max-Count yet not encrypted.\n"); + err = -2; + goto end; + } + if (reached_maxcount(digest, maxcount)) { + if (testto->length == 0) + errlog(LOG, "Max-Count reached - discarding message.\n"); + buf_appends(test, "Max-Count reached - discarding message.\n"); + err = -2; + goto end; + } + } + + if (type == MSG_POST && subject->length == 0) + buf_sets(subject, "(no subject)"); + + if (to->length > 0) + buf_appendf(out, "To: %b\n", to); + else if (remixto->length > 0) + buf_appendf(out, "To: %b\n", remixto); + if (newsgroups->length > 0) + buf_appendf(out, "Newsgroups: %b\n", newsgroups); + if (subject->length > 0) { +#ifdef USE_IDEA + if (esub->length > 0) + t1_esub(esub, subject); +#endif /* USE_IDEA */ + buf_appendf(out, "Subject: %b\n", subject); + } + buf_cat(out, header); + buf_nl(out); + +#if 0 + inflate -= in->length; +#endif /* 0 */ + if (inflate > 0) { + buf_setrnd(temp, inflate * 3 / 4); + encode(temp, 64); + buf_appends(in, "\n-----BEGIN GARBAGE-----\n"); + buf_cat(in, temp); + buf_appends(in, "-----END GARBAGE-----\n"); + } + + if (!(ek->length || ekdes->length || ekcast->length)) + buf_rest(out, in); + else { + err = 0; + buf_clear(temp); + while (buf_getline(in, line) != -1) { + if (isline(line, EKMARK)) { + buf_cat(out, temp); + buf_clear(temp); + buf_rest(temp, in); + break; + } + else { + buf_cat(temp, line); + buf_nl(temp); + } + } +#ifdef USE_PGP + if (ekcast->length) { + err = pgp_encrypt(PGP_CONVCAST | PGP_TEXT, temp, ekcast, NULL, NULL, + NULL, NULL); + buf_clear(ekcast); + } + if (ekdes->length) { + err = pgp_encrypt(PGP_CONV3DES | PGP_TEXT, temp, ekdes, NULL, NULL, + NULL, NULL); + buf_clear(ekdes); + } + if (ek->length) { + err = pgp_encrypt(PGP_CONVENTIONAL | PGP_TEXT, temp, ek, NULL, NULL, + NULL, NULL); + buf_clear(ek); + } + buf_appends(out, EKMARK); + buf_nl(out); + buf_cat(out, temp); +#else /* end of USE_PGP */ + err = -1; +#endif /* Else if not USE_PGP */ + } + + if (type == -1) { + buf_appends(test, "No destination.\n"); + err = -1; + } + +end: + if (testto->length) { + BUFFER *report; + int i; + + report = buf_new(); + buf_sets(report, + "Subject: remailer test report\n\nThis is an automated response to the test message you sent to "); + buf_appends(report, SHORTNAME); + buf_appends(report, ".\nYour test message results follow:\n\n"); + buf_appends(report, remailer_type); + buf_appends(report, VERSION); + buf_appends(report, "\n\n"); + if (err == 0) { + err = filtermsg(out); + if (err == -1) + buf_appends(report, "This remailer cannot deliver the message.\n\n"); + else { + buf_appends(report, "Valid "); + buf_appends(report, type == MSG_POST ? "Usenet" : "mail"); + buf_appends(report, " message.\n"); + if (remixto->length) { + if (remix && MIX) + buf_appends(report, "Delivery via Mixmaster: "); + else if (remix) + buf_appends(report, "Error! Can't remix: "); + else + buf_appends(report, "Delivery via Cypherpunk remailer: "); + buf_cat(report, remixto); + buf_nl(report); + } + else if (type == MSG_POST && strchr(NEWS, '@') && !strchr(NEWS, ' ')) { + buf_appendf(report, "News gateway: %s\n", NEWS); + } + buf_appends(report, + "\n=========================================================================\nThe first 20 lines of the message follow:\n"); + if (err != 1) + buf_appendf(report, "From: %s\n", ANONNAME); + if (type == MSG_POST && ORGANIZATION[0] != '\0') + buf_appendf(report, "Organization: %s\n", ORGANIZATION); + } + for (i = 0; i < 20 && buf_getline(out, test) != -1; i++) + buf_cat(report, test), buf_nl(report); + } else { + buf_appends(report, "The remailer message is invalid.\n\n"); + if (test->length) { + buf_appends(report, "The following error occurred: "); + buf_cat(report, test); + buf_nl(report); + } + } + buf_appends(report, + "=========================================================================\nThe first 20 lines of your message to the remailer follow:\n"); + buf_rewind(in); + for (i = 0; i < 20 && buf_getline(in, test) != -1; i++) + buf_cat(report, test), buf_nl(report); + + sendmail(report, REMAILERNAME, testto); + err = 0; + buf_free(report); + } else if (err == 0 && type != MSG_NULL) { + err = 1; + if (bufieq(to, REMAILERADDR)) /* don't remix to ourselves */ + remix = 0; + if (remix && remixto->length == 0) + buf_set(remixto, to); + if (remixto->length > 0) { + /* check that the remix-to path isn't too long */ + int remixcount = 1; + char *tmp = remixto->data; + while ((tmp = strchr(tmp+1, ','))) { + remixcount ++; + if (remixcount > MAXRANDHOPS) { + *tmp = '\0'; + break; + } + }; + } + if (remix && !repgp && remixto->length != 0) + err = mix_encrypt(type, out, remixto->data, 1, line); + if (err != 0) { + if (remix == 1 && !repgp) + errlog(NOTICE, "Can't remix -- %b\n", line); + else { + if (remixto->length) + err = t1_encrypt(type, out, remixto->data, 0, 0, line); + if (err != 0 && repgp) + errlog(NOTICE, "Can't repgp -- %b\n", line); + else + err = mix_pool(out, type, latent * 60); + } + } + } + + buf_free(field); + buf_free(content); + buf_free(line); + buf_free(to); + buf_free(remixto); + buf_free(newsgroups); + buf_free(subject); + buf_free(ek); + buf_free(ekcast); + buf_free(ekdes); + buf_free(esub); + buf_free(cutmarks); + buf_free(temp); + buf_free(out); + buf_free(header); + buf_free(test); + buf_free(testto); + buf_free(digest); + return (err); +} diff --git a/Src/rem2.c b/Src/rem2.c @@ -0,0 +1,486 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Process Mixmaster remailer messages + $Id: rem2.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <string.h> +#include <time.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef POSIX +#include <unistd.h> +#else /* end of POSIX */ +#include <io.h> +#endif /* else if not POSIX */ +#ifndef _MSC +#include <dirent.h> +#endif /* not _MSC */ +#include <assert.h> + +int mix_dearmor(BUFFER *in, BUFFER *out) +{ + BUFFER *line, *md; + int tempbuf = 0; + int err = 0; + + line = buf_new(); + md = buf_new(); + + if (in == out) { + tempbuf = 1; + out = buf_new(); + } + do { + err = buf_getline(in, line); + if (err == -1) + goto end; + } + while (!bufeq(line, begin_remailer)); + + do { + /* skip lines before message digest */ + if (buf_getline(in, md) == -1) + break; + } while (strlen(md->data) != 24); + + decode(in, out); + + err = buf_getline(in, line); + if (err != 0 || !bufeq(line, end_remailer)) + err = -1; + else { + digest_md5(out, line); + encode(line, 0); + if (!buf_eq(md, line)) + err = -1; + if (out->length != 20480) + err = -1; + } + +end: + if (err == -1) + errlog(NOTICE, "Malformatted message.\n"); + + if (tempbuf) { + buf_move(in, out); + buf_free(out); + } + buf_free(line); + buf_free(md); + return (err); +} + +static int isnewid(BUFFER *id, long timestamp) +/* return values: + * 0: ignore message, no error + * 1: ok, process message + * -1: bad message, send reply + */ +{ + FILE *f; + int ret = 1; + long now, old = 0; + LOCK *i = NULL; + idlog_t idbuf; + + if (REMAIL == 0) + return (1); /* don't keep statistics for the client */ + + now = time(NULL); + + if ((f = mix_openfile(IDLOG, "rb+")) != NULL) { + fread(&idbuf,1,sizeof(idlog_t),f); + old = idbuf.time; + } else { + if (IDEXP == 0) { + if (timestamp > 0 && timestamp <= now - 7 * SECONDSPERDAY) { + errlog(LOG, "Ignoring old message.\n"); + return (0); + } + } else { + if ((f = mix_openfile(IDLOG, "wb")) != NULL) { + memset(idbuf.id,0,sizeof(idbuf.id)); + idbuf.time = now; + fwrite(&idbuf,1,sizeof(idlog_t),f); + memcpy(idbuf.id,id->data,sizeof(idbuf.id)); + idbuf.time = now; + fwrite(&idbuf,1,sizeof(idlog_t),f); + fclose(f); + errlog(NOTICE, "Creating %s\n", IDLOG); + } else { + errlog(ERRORMSG, "Can't create %s\n", IDLOG); + } + return (1); + } + } + + if (now - old < 5 * SECONDSPERDAY) /* never reject messages less than */ + old = now - 5 * SECONDSPERDAY; /* 5 days old (== minimum IDEXP) */ + + if (timestamp > 0 && timestamp <= old) { + errlog(LOG, "Ignoring old message.\n"); + ret = 0; + goto end; + } + i = lockfile(IDLOG); + while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) { + if (!memcmp(idbuf.id, id->data, sizeof(idbuf.id))) { + char idstr[33]; + id_encode(id->data, idstr); + errlog(LOG, "Ignoring redundant message: %s.\n", idstr); + ret = 0; + goto end; + } + } + if (timestamp > now) { + errlog(LOG, "Ignoring message with future timestamp.\n"); + ret = -1; + goto end; + } + if (ftell(f)%sizeof(idlog_t)) fseek(f,0-(ftell(f)%sizeof(idlog_t)),SEEK_CUR); /* make sure that we're on sizeof(idlog_t) byte boundary */ + memcpy(idbuf.id,id->data,sizeof(idbuf.id)); + idbuf.time = now; + fwrite(&idbuf,1,sizeof(idlog_t),f); +end: + if (i) + unlockfile(i); + fclose(f); + return (ret); +} + +int mix2_decrypt(BUFFER *m) + /* 0: ok + * -1: error + * -2: old message */ +{ + int err = 0; + int i; + BUFFER *privkey; + BUFFER *keyid; + BUFFER *dec, *deskey; + BUFFER *packetid, *mid, *digest, *addr, *temp, *iv, *ivvec; + int type, packet = 0, numpackets = 0, timestamp = 0; + BUFFER *body; + BUFFER *header, *out; + + privkey = buf_new(); + keyid = buf_new(); + dec = buf_new(); + deskey = buf_new(); + packetid = buf_new(); + mid = buf_new(); + digest = buf_new(); + addr = buf_new(); + temp = buf_new(); + iv = buf_new(); + ivvec = buf_new(); + body = buf_new(); + header = buf_new(); + out = buf_new(); + + buf_get(m, keyid, 16); + err = db_getseckey(keyid->data, privkey); + if (err == -1) + goto end; + buf_get(m, deskey, buf_getc(m)); + err = pk_decrypt(deskey, privkey); + if (err == -1 || deskey->length != 24) { + err = -1; + errlog(NOTICE, "Cannot decrypt message.\n"); + goto end; + } + buf_get(m, iv, 8); + buf_get(m, dec, 328); + buf_crypt(dec, deskey, iv, DECRYPT); + buf_get(dec, packetid, 16); + buf_get(dec, deskey, 24); + type = buf_getc(dec); + switch (type) { + case 0: + buf_get(dec, ivvec, 152); + buf_get(dec, addr, 80); + break; + case 1: + buf_get(dec, mid, 16); + buf_get(dec, iv, 8); + break; + case 2: + packet = buf_getc(dec); + numpackets = buf_getc(dec); + buf_get(dec, mid, 16); + buf_get(dec, iv, 8); + break; + default: + errlog(WARNING, "Unknown message type.\n"); + err = -1; + goto end; + } + if (dec->data[dec->ptr] == '0' && dec->data[dec->ptr + 1] == '0' && + dec->data[dec->ptr + 2] == '0' && dec->data[dec->ptr + 3] == '0' && + dec->data[dec->ptr + 4] == '\0') { + dec->ptr += 5; + timestamp = buf_geti_lo(dec); + } else { + errlog(LOG, "Ignoring message without timestamp.\n"); + err = -1; + goto end; + } + buf_get(dec, digest, 16); + + dec->length = dec->ptr - 16; /* ignore digest */ + dec->ptr = dec->length; + + if (!isdigest_md5(dec, digest)) { + errlog(NOTICE, "Message digest does not match.\n"); + err = -1; + goto end; + } + switch (isnewid(packetid, timestamp * SECONDSPERDAY)) { + case 0: err = -2; /* redundant message */ + goto end; + case -1: err = -1; /* future timestamp */ + goto end; + } + buf_append(body, m->data + 20 * 512, 10240); + + switch (type) { + case 0: + buf_chop(addr); + buf_cat(out, addr); + buf_nl(out); + for (i = 0; i < 19; i++) { + buf_reset(header); + buf_append(header, m->data + (i + 1) * 512, 512); + buf_reset(iv); + buf_append(iv, ivvec->data + i * 8, 8); + buf_crypt(header, deskey, iv, DECRYPT); + buf_cat(out, header); + } + buf_reset(header); + buf_pad(header, 512); + buf_cat(out, header); + buf_reset(iv); + buf_append(iv, ivvec->data + 144, 8); + buf_crypt(body, deskey, iv, DECRYPT); + buf_cat(out, body); + mix_pool(out, INTERMEDIATE, -1); + break; + case 1: + buf_crypt(body, deskey, iv, DECRYPT); + err = v2body_setlen(body); + if (err == -1) + goto end; + assert(body->ptr == 4); + v2body(body); + break; + case 2: + buf_crypt(body, deskey, iv, DECRYPT); + v2partial(body, mid, packet, numpackets); + break; + } +end: + buf_free(privkey); + buf_free(keyid); + buf_free(dec); + buf_free(deskey); + buf_free(packetid); + buf_free(mid); + buf_free(digest); + buf_free(addr); + buf_free(temp); + buf_free(iv); + buf_free(ivvec); + buf_free(body); + buf_free(header); + buf_free(out); + + return (err); +} + +int v2body_setlen(BUFFER *body) +{ + long length; + + length = buf_getl_lo(body); + if (length < 0 || length > body->length) + return (-1); + body->length = length + 4; + return (0); +} + +int v2body(BUFFER *body) +{ + int i, n; + BUFFER *to, *newsgroups; + BUFFER *temp, *out; + BUFFER *line; + int type = MSG_MAIL; + int subject = 0; + + line = buf_new(); + to = buf_new(); + newsgroups = buf_new(); + temp = buf_new(); + out = buf_new(); + + n = buf_getc(body); + for (i = 0; i < n; i++) { + buf_get(body, line, 80); + buf_chop(line); + if (bufileft(line, "null:")) + goto end; + if (bufileft(line, "post:")) { + type = MSG_POST; + if (line->length > 5) { + int j = 5; + + while (j < line->length && isspace(line->data[j])) + j++; + if (newsgroups->length > 0) + buf_appends(newsgroups, ","); + buf_append(newsgroups, line->data + j, line->length - j); + } + } else { + if (to->length > 0) + buf_appends(to, ","); + buf_cat(to, line); + } + } + if (to->length > 0) { + buf_appends(out, "To: "); + buf_cat(out, to); + buf_nl(out); + } + if (newsgroups->length > 0) { + buf_appends(out, "Newsgroups: "); + buf_cat(out, newsgroups); + buf_nl(out); + } + n = buf_getc(body); + for (i = 0; i < n; i++) { + buf_get(body, line, 80); + buf_chop(line); + if (bufileft(line, "Subject:")) + subject = 1; + buf_cat(out, line); + buf_nl(out); + } + + buf_rest(temp, body); + buf_uncompress(temp); + buf_set(body, temp); + buf_reset(temp); + + if (buf_lookahead(body, line) == 0 && isline(line, HASHMARK)) { + buf_getline(body, line); + while (buf_getline(body, line) == 0) { + if (bufileft(line, "subject:")) + subject = 1; + buf_cat(out, line); + buf_nl(out); + } + } + if (type == MSG_POST && !subject) + buf_appends(out, "Subject: (no subject)\n"); + + buf_nl(out); + buf_rest(out, body); + buf_reset(body); + mix_pool(out, type, -1); + +end: + buf_free(line); + buf_free(to); + buf_free(newsgroups); + buf_free(temp); + buf_free(out); + return (0); +} + +int v2_merge(BUFFER *mid) +{ + char fname[PATHMAX], line[LINELEN]; + BUFFER *temp, *msg; + FILE *l, *f; + int i, numpackets; + struct stat sb; + long d; + int n; + int err = -1; + + temp = buf_new(); + msg = buf_new(); + pool_packetfile(fname, mid, 0); + l = fopen(fname, "a+"); + if (l != NULL) + lock(l); + + pool_packetfile(fname, mid, 1); + f = fopen(fname, "rb"); + if (f == NULL) + goto end; + fscanf(f, "%32s %ld %d %d\n", line, &d, &i, &numpackets); + fclose(f); + + /* do we have all packets? */ + for (i = 1; i <= numpackets; i++) { + pool_packetfile(fname, mid, i); + if (stat(fname, &sb) != 0) + goto end; + } + errlog(LOG, "Reassembling multipart message.\n"); + for (i = 1; i <= numpackets; i++) { + pool_packetfile(fname, mid, i); + f = fopen(fname, "rb"); + if (f == NULL) + goto end; + fscanf(f, "%32s %ld %d %d\n", line, &d, &n, &n); + buf_clear(temp); + buf_read(temp, f); + v2body_setlen(temp); + buf_append(msg, temp->data + 4, temp->length - 4); + fclose(f); + unlink(fname); + } + err = v2body(msg); + +end: + if (l != NULL) + fclose(l); + pool_packetfile(fname, mid, 0); + unlink(fname); + buf_free(temp); + buf_free(msg); + return (err); +} + +int v2partial(BUFFER *m, BUFFER *mid, int packet, int numpackets) +{ + char fname[PATHMAX], idstr[33]; + FILE *f; + int err = 1; + + pool_packetfile(fname, mid, packet); + f = fopen(fname, "wb"); + if (f == NULL) { + err = -1; + goto end; + } + id_encode(mid->data, idstr); + fprintf(f, "%s %ld %d %d\n", idstr, (long) time(NULL), packet, + numpackets); + buf_write(m, f); + buf_reset(m); + fclose(f); + v2_merge(mid); +end: + return (err); +} diff --git a/Src/remailer.c b/Src/remailer.c @@ -0,0 +1,36 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Simple remailer frontend: Read mix packets from standard input. + $Id: remailer.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix.h" +#include <stdio.h> + +/** main *****************************************************************/ + +/* Returns: + 0 successful operation + 1 error */ + +int main(int argc, char *argv[]) +{ + BUFFER *msg; + int ret; + + mix_init(NULL); + msg = buf_new(); + ret = buf_read(msg, stdin); + if (ret != -1) + ret = mix_decrypt(msg); + + mix_regular(0); + mix_exit(); + buf_free(msg); + return (ret == 0 ? 0 : 1); +} diff --git a/Src/rfc822.c b/Src/rfc822.c @@ -0,0 +1,585 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Parse RFC 822 headers + $Id: rfc822.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" + +static int is_specials(int c); +static int is_qtext(char c); +static int is_ctext(char c); +static void wsc(BUFFER *in, BUFFER *xomment); +static int word(BUFFER *in, BUFFER *word, BUFFER *x); +static int atom(BUFFER *in, BUFFER *atom, BUFFER *x); +static int quoted_string(BUFFER *in, BUFFER *string, BUFFER *x); +static int comment(BUFFER *in, BUFFER *string); +static int local_part(BUFFER *in, BUFFER *addr, BUFFER *x); +static int domain(BUFFER *in, BUFFER *domain, BUFFER *x); +static int sub_domain(BUFFER *in, BUFFER *sub, BUFFER *x); +static int domain_ref(BUFFER *in, BUFFER *dom, BUFFER *x); +static int domain_literal(BUFFER *in, BUFFER *dom, BUFFER *x); +static int addr_spec(BUFFER *in, BUFFER *addr, BUFFER *x); +static int route_addr(BUFFER *in, BUFFER *addr, BUFFER *x); +static int phrase(BUFFER *in, BUFFER *phr, BUFFER *x); +static int mailbox(BUFFER *in, BUFFER *mailbox, BUFFER *name, BUFFER *x); +static int group(BUFFER *in, BUFFER *group, BUFFER *name, BUFFER *x); + +static void backtrack(BUFFER *b, int len) +{ + if (b) { + b->length = len; + b->data[b->length] = '\0'; + } +} + +/* white space and comments */ +static void wsc(BUFFER *in, BUFFER *string) +{ + int c; + + for (;;) { + c = buf_getc(in); + if (c == -1) + break; + else if (c == '\n') { + c = buf_getc(in); + if (c != ' ' && c != '\t') { + if (c != -1) + buf_ungetc(in), buf_ungetc(in); + break; + } + } else { + if (c != ' ' && c != '\t') { + buf_ungetc(in); + if (!comment(in, string)) + break; + } + } + } +} + +/* specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted- + * / "," / ";" / ":" / "\" / <"> ; string, to use + * / "." / "[" / "]" ; within a word. + */ + +static int is_specials(int c) +{ + return (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || + c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' || + c == '.' || c == '[' || c == ']'); +} + +/* qtext = <any CHAR excepting <">, ; => may be folded + * "\" & CR, and including + * linear-white-space> + */ +static int is_qtext(char c) +{ + return (c != '\"' && c != '\\' && c != '\n'); +} + +/* ctext = <any CHAR excluding "(", ; => may be folded + * ")", "\" & CR, & including + * linear-white-space> + */ +static int is_ctext(char c) +{ + return (c != '(' && c != ')' && c != '\\' && c != '\n'); +} + +/* word = atom / quoted-string + */ +static int word(BUFFER *in, BUFFER *word, BUFFER *x) +{ + return (atom(in, word, x) || quoted_string(in, word, x)); +} + +/* atom = 1*<any CHAR except specials, SPACE and CTLs> + */ +static int atom(BUFFER *in, BUFFER *atom, BUFFER *x) +{ + int c; + + buf_clear(atom); + wsc(in, x); + for (;;) { + c = buf_getc(in); + if (c == -1) + break; + else if (is_specials(c) || c == ' ' || c < 32 || c == 127) { + buf_ungetc(in); + break; + } else + buf_appendc(atom, c); + } + if (atom->length) + wsc(in, x); + return (atom->length); +} + +/* quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or + * ; quoted chars. + */ +static int quoted_string(BUFFER *in, BUFFER *string, BUFFER *x) +{ + int ptr, xlen; + int c; + + ptr = in->ptr, xlen = x ? x->length : 0; + buf_clear(string); + wsc(in, NULL); + c = buf_getc(in); + if (c == '\"') { +#if 0 + buf_appendc(string, c); +#endif + for (;;) { + c = buf_getc(in); + if (c == -1) /* catch unterminated quoted string */ + break; + if (is_qtext(c)) + buf_appendc(string, c); + else if (c == '\n') { + c = buf_getc(in); + if (c != ' ' && c != '\n') + break; + } else if (c == '\\') { + c = buf_getc(in); + if (c == -1) + break; + else + buf_appendc(string, c); + } else if (c == '\"') { +#if 0 + buf_appendc(string, c); +#endif + wsc(in, NULL); + return (1); + } else + break; + } + } + in->ptr = ptr, backtrack(x, xlen); + return (0); +} + +/* comment = "(" *(ctext / quoted-pair / comment) ")" + */ +static int comment(BUFFER *in, BUFFER *string) +{ + int ptr, xlen; + int separator = 0; + int c; + + ptr = in->ptr; + xlen = string ? string->length : 0; + if (xlen) + separator = 1; + c = buf_getc(in); + if (c == '(') { + for (;;) { + c = buf_getc(in); + if (c == -1) + return(1); /* unterminated comment, bail out */ + if (is_ctext(c)) { + if (string != NULL) { + if (separator) + buf_appendc(string, ' '), separator = 0; + buf_appendc(string, c); + } + } else if (c == '\n') { + c = buf_getc(in); + if (c != ' ' && c != '\n') + break; + } else if (c == '\\') { + c = buf_getc(in); + if (c != -1) { + if (string != NULL) { + if (separator) + buf_appendc(string, ' '), separator = 0; + buf_appendc(string, c); + } + } + } else if (c == ')') + return (1); + else { + BUFFER *s; + int o; + + s = buf_new(); + buf_ungetc(in); + o = comment(in, s); + if (o && string != NULL) { + if (separator) + buf_appendc(string, ' '), separator = 0; + buf_cat(string, s); + } + buf_free(s); + if (!o) + break; + } + } + } + in->ptr = ptr; + backtrack(string, xlen); + return (0); +} + +/* local-part = word *("." word) ; uninterpreted + * ; case-preserved + */ +static int local_part(BUFFER *in, BUFFER *addr, BUFFER *x) +{ + BUFFER *w; + int c; + + buf_clear(addr); + if (!word(in, addr, x)) + return (0); + w = buf_new(); + for (;;) { + c = buf_getc(in); + if (c == -1) + break; + if (c == '.' && (word(in, w, x))) + buf_appendc(addr, '.'), buf_cat(addr, w); + else { + buf_ungetc(in); + break; + } + } + buf_free(w); + return (addr->length); +} + +/* domain = sub-domain *("." sub-domain) + */ +static int domain(BUFFER *in, BUFFER *domain, BUFFER *x) +{ + BUFFER *sub; + int c; + + if (!sub_domain(in, domain, x)) + return (0); + sub = buf_new(); + for (;;) { + c = buf_getc(in); + if (c == -1) + break; + if (c == '.' && (sub_domain(in, sub, x))) + buf_appendc(domain, '.'), buf_cat(domain, sub); + else { + buf_ungetc(in); + break; + } + } + buf_free(sub); + return (domain->length); +} + +/* sub-domain = domain-ref / domain-literal + */ +static int sub_domain(BUFFER *in, BUFFER *sub, BUFFER *x) +{ + return (domain_ref(in, sub, x) || domain_literal(in, sub, x)); +} + +/* domain-ref = atom ; symbolic reference + */ +static int domain_ref(BUFFER *in, BUFFER *d, BUFFER *x) +{ + return (atom(in, d, x)); +} + +/* addr-spec = local-part "@" domain ; global address + */ +static int addr_spec(BUFFER *in, BUFFER *addr, BUFFER *x) +{ + BUFFER *dom; + int ptr, xlen; + + ptr = in->ptr, xlen = x ? x->length : 0; + dom = buf_new(); + buf_clear(addr); + if (local_part(in, addr, x) && buf_getc(in) == '@' && domain(in, dom, x)) + buf_appendc(addr, '@'), buf_cat(addr, dom); + else + buf_clear(addr), in->ptr = ptr, backtrack(x, xlen); + buf_free(dom); + return (addr->length); +} + +/* route-addr = "<" [route] addr-spec ">" + */ +static int route_addr(BUFFER *in, BUFFER *addr, BUFFER *x) +{ + int c; + int ptr, xlen; + + ptr = in->ptr, xlen = x ? x->length : 0; + c = buf_getc(in); + if (c == -1) + return (0); + if (c != '<') { + buf_ungetc(in); + return (0); + } + if (addr_spec(in, addr, x) && buf_getc(in) == '>') + return (1); + in->ptr = ptr, backtrack(x, xlen); + return (0); +} + +/* phrase = 1*word ; Sequence of words + */ +static int phrase(BUFFER *in, BUFFER *phr, BUFFER *x) +{ + BUFFER *w; + + buf_clear(phr); + w = buf_new(); + while (word(in, w, x)) { + if (phr->length) + buf_appendc(phr, ' '); + buf_cat(phr, w); + } + buf_free(w); + return (phr->length); +} + +/* mailbox = addr-spec ; simple address + * / [phrase] route-addr ; name & addr-spec + * (RFC 1123) + */ +static int mailbox(BUFFER *in, BUFFER *mailbox, BUFFER *name, BUFFER *x) +{ + int ptr, xlen, ret; + + buf_clear(name); + if (addr_spec(in, mailbox, x)) + return (1); + + ptr = in->ptr, xlen = x ? x->length : 0; + ret = phrase(in, name, x) && route_addr(in, mailbox, x); + if (!ret) { + in->ptr = ptr, backtrack(x, xlen); + ret = route_addr(in, mailbox, x); + } + + return (ret); +} + +/* address = mailbox ; one addressee + * / group ; named list + */ +static int address(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x) +{ + return (mailbox(in, address, name, x) || group(in, address, name, x)); +} + +/* group = phrase ":" [#mailbox] ";" + */ +static int group(BUFFER *in, BUFFER *group, BUFFER *name, BUFFER *x) +{ + BUFFER *addr, *tmp; + int ptr, xlen, ret = 0; + + ptr = in->ptr, xlen = x ? x->length : 0; + addr = buf_new(); + tmp = buf_new(); + buf_clear(group); + if (phrase(in, name, x) && buf_getc(in) == ':') { + while (mailbox(in, addr, tmp, x)) + buf_cat(group, addr), buf_nl(group); + ret = buf_getc(in) == ';'; + } + if (!ret) + in->ptr = ptr, backtrack(x, xlen); + buf_free(addr); + buf_free(tmp); + return (ret); +} + +/* domain-literal = "[" *(dtext / quoted-pair) "]" + */ +static int domain_literal(BUFFER *in, BUFFER *dom, BUFFER *x) +{ + return 0; /* XXX */ +} + +/* local address without `@' is not specified in RFC 822 */ + +/* local_addr = "<" atom ">" */ +static int local_addr(BUFFER *in, BUFFER *addr, BUFFER *x) +{ + int c; + int ptr, xlen; + + ptr = in->ptr, xlen = x ? x->length : 0; + c = buf_getc(in); + if (c == -1) + return (0); + if (c != '<') { + buf_ungetc(in); + return (0); + } + if (atom(in, addr, x) && buf_getc(in) == '>') + return (1); + in->ptr = ptr, backtrack(x, xlen); + return (0); +} + +static int localaddress(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x) +{ + int ptr, xlen; + + buf_clear(name); + if (local_addr(in, address, x)) + return (1); + ptr = in->ptr, xlen = x ? x->length : 0; + if (phrase(in, name, x) && local_addr(in, address, x)) + return (1); + in->ptr = ptr, backtrack(x, xlen); + buf_clear(name); + return (atom(in, address, x)); +} + +void rfc822_addr(BUFFER *destination, BUFFER *list) +{ + BUFFER *addr, *name; + + addr = buf_new(); + name = buf_new(); + + for (;;) { + if (!address(destination, addr, name, NULL) && + !localaddress(destination, addr, name, NULL)) + break; + buf_cat(list, addr); + buf_nl(list); + if (buf_getc(destination) != ',') + break; + } + buf_free(addr); + buf_free(name); +} + +void rfc822_name(BUFFER *line, BUFFER *name) +{ + BUFFER *addr, *comment; + int ret; + + addr = buf_new(); + comment = buf_new(); + ret = address(line, addr, name, comment); + if (ret == 0) + ret = localaddress(line, addr, name, comment); + if (ret) { + if (name->length == 0) + buf_set(name, comment); + if (name->length == 0) + buf_set(name, addr); + } + if (ret == 0) + buf_set(name, line); + buf_free(addr); + buf_free(comment); +} + +/* MIME extensions. RFC 2045 */ + +/* tspecials := "(" / ")" / "<" / ">" / "@" / + * "," / ";" / ":" / "\" / <"> + * "/" / "[" / "]" / "?" / "=" + */ + +static int is_tspecials(int c) +{ + return (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || + c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' || + c == '/' || c == '[' || c == ']' || c == '?' || c == '='); +} + +/* token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, + * or tspecials> + */ +static int token(BUFFER *in, BUFFER *token, BUFFER *x) +{ + int c; + + buf_clear(token); + wsc(in, x); + for (;;) { + c = buf_getc(in); + if (c == -1) + break; + else if (is_tspecials(c) || c == ' ' || c < 32 || c == 127) { + buf_ungetc(in); + break; + } else + buf_appendc(token, c); + } + if (token->length) + wsc(in, x); + return (token->length); +} + +/* value := token / quoted-string + */ + +static int value(BUFFER *in, BUFFER *value, BUFFER *x) +{ + return (token(in, value, x) || quoted_string(in, value, x)); +} + +/* parameter := attribute "=" value + */ + +static int parameter(BUFFER *in, BUFFER *attribute, BUFFER *val, BUFFER *x) +{ + int ptr; + ptr = in->ptr; + token(in, attribute, x); + if (buf_getc(in) != '=') { + in->ptr = ptr; + return(0); + } + return(value(in, val, x)); +} + +/* get type */ +int get_type(BUFFER *content, BUFFER *type, BUFFER *subtype) +{ + token(content, type, NULL); + if (buf_getc(content) == '/') + return (token(content, subtype, NULL)); + buf_ungetc(content); + buf_clear(type); + return (0); +} + +/* get parameter value */ +void get_parameter(BUFFER *content, char *attribute, BUFFER *value) +{ + BUFFER *tok; + tok = buf_new(); + buf_clear(value); + + get_type(content, tok, tok); + for (;;) { + if (buf_getc(content) != ';') + break; + if (parameter(content, tok, value, NULL) && + strieq(attribute, tok->data)) + break; /* found */ + buf_clear(value); + } + buf_free(tok); +} diff --git a/Src/rndseed.c b/Src/rndseed.c @@ -0,0 +1,157 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Get randomness from device or user + $Id: rndseed.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <assert.h> +#include <time.h> +#include <fcntl.h> +#include <time.h> +#include <stdlib.h> +#ifdef POSIX +#include <unistd.h> +#include <termios.h> +#else /* end of POSIX */ +#include <io.h> +#include <process.h> +#endif /* else if not POSIX */ +#if defined(WIN32) || defined(MSDOS) +#include <conio.h> +#endif /* defined(WIN32) || defined(MSDOS) */ +#ifdef WIN32 +#include <windows.h> +#endif /* WIN32 */ + +#define NEEDED 128 + +#ifndef O_NDELAY +#define O_NDELAY 0 +#endif /* not O_NDELAY */ + +int kbd_noecho(void) +{ +#ifdef HAVE_TERMIOS + int fd; + struct termios attr; + + setbuf(stdin, NULL); + fd = fileno(stdin); + if (tcgetattr(fd, &attr) != 0) + return (-1); + attr.c_lflag &= ~(ECHO | ICANON); + if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) + return (-1); +#endif /* HAVE_TERMIOS */ + return (0); +} + +int kbd_echo(void) +{ +#ifdef HAVE_TERMIOS + int fd; + struct termios attr; + + setvbuf(stdin, NULL, _IOLBF, BUFSIZ); + fd = fileno(stdin); + if (tcgetattr(fd, &attr) != 0) + return (-1); + attr.c_lflag |= ECHO | ICANON; + if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) + return (-1); +#endif /* HAVE_TERMIOS */ + return (0); +} + +void rnd_error(void) +{ + errlog(ERRORMSG, + "Random number generator not initialized. Aborting.\n\ +Run the program interactively to seed the generator.\n"); + exit(3); +} + +/* get randomness from system or user. If the application has promised that + it will seed the RNG later, we do not ask for user input */ + +int rnd_seed(void) +{ + int fd = -1; + byte b[512], c = 0; + int bytes = 0; + +#ifdef DEV_RANDOM + fd = open(DEV_RANDOM, O_RDONLY | O_NDELAY); +#endif /* DEV_RANDOM */ + if (fd == -1) { +#if 1 + if (rnd_state == RND_WILLSEED) + return(-1); + if (!isatty(fileno(stdin))) + rnd_error(); +#else /* end of 1 */ +#error "should initialize the prng from system ressources" +#endif /* else if not 1 */ + fprintf(stderr, "Please enter some random characters.\n"); + kbd_noecho(); + while (bytes < NEEDED) { + fprintf(stderr, " %d \r", NEEDED - bytes); +#ifdef HAVE_GETKEY + if (kbhit(), *b = getkey()) +#else /* end of HAVE_GETKEY */ + if (read(fileno(stdin), b, 1) > 0) +#endif /* else if not HAVE_GETKEY */ + { + rnd_add(b, 1); + rnd_time(); + if (*b != c) + bytes++; + c = *b; + } + } + fprintf(stderr, "Thanks.\n"); + sleep(1); + kbd_echo(); + } +#ifdef DEV_RANDOM + else { + bytes = read(fd, b, sizeof(b)); + if (bytes > 0) { + rnd_add(b, bytes); + } else { + bytes = 0; + } + close(fd); + if (bytes < NEEDED) { + fd = open(DEV_RANDOM, O_RDONLY); /* re-open in blocking mode */ + if (isatty(fileno(stdin))) { + fprintf(stderr, + "Please move the mouse, enter random characters, etc.\n"); + kbd_noecho(); + } + while (bytes < NEEDED) { + if (isatty(fileno(stdin))) + fprintf(stderr, " %d \r", NEEDED - bytes); + if (read(fd, b, 1) > 0) { + rnd_add(b, 1); + bytes++; + } + } + if (isatty(fileno(stdin))) { + fprintf(stderr, "Thanks.\n"); + sleep(1); + kbd_echo(); + } + close(fd); + } + } +#endif /* DEV_RANDOM */ + rnd_state = RND_SEEDED; + return (0); +} diff --git a/Src/service.c b/Src/service.c @@ -0,0 +1,331 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Win32 Service support + $Id: service.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include <windows.h> +#include <stdio.h> +#include <direct.h> +#include <io.h> +#include <fcntl.h> + +#include "mix3.h" + +#ifdef WIN32SERVICE + +#define SVCNAME "Mixmaster" +#define SVCDISPLAYNAME "Mixmaster Service" + + +/* internal variables */ +static SERVICE_STATUS ssStatus; +static SERVICE_STATUS_HANDLE sshStatusHandle; +static BOOL not_service = FALSE; + +static HANDLE hThread = NULL; +static HANDLE hMustTerminate = NULL; + +/* internal function prototypes */ +VOID WINAPI service_ctrl(DWORD ctrl_code); +VOID WINAPI service_main(DWORD argc, LPSTR *argv); +static DWORD service_run(void); +static void service_stop(); +static int set_stdfiles(); +static int install_service(); +static int remove_service(); +static int run_notservice(int argc, char **argv); +BOOL WINAPI console_ctrl_handler(DWORD ctrl_type); +static char *GetLastErrorText(); +static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id); +static void event_log(DWORD id, char *eventmsg); + +int mix_main(int argc, char *argv[]); + + +int main(int argc, char *argv[]) +{ + SERVICE_TABLE_ENTRY dispatchTable[] = { + {SVCNAME, (LPSERVICE_MAIN_FUNCTION)service_main}, + {NULL, NULL} }; + + if ((argc > 1) && ((argv[1][0] == '-') && (argv[1][1] == '-'))) { + if (!_stricmp("install-svc", argv[1]+2)) + return install_service(); + else if (!_stricmp("remove-svc", argv[1]+2)) + return remove_service(); + else if (_stricmp("run-svc", argv[1]+2) && !is_nt_service()) + return run_notservice(argc, argv); + } else if (!is_nt_service()) { + return run_notservice(argc, argv); + } + printf("mix --install-svc install the service\n"); + printf("mix --remove-svc remove the service\n"); + printf("mix --run-svc run as a service\n"); + printf("mix -h view a summary of the command line options.\n"); + + printf("\nStartServiceCtrlDispatcher being called.\n" ); + printf("This may take several seconds. Please wait.\n" ); + if (!StartServiceCtrlDispatcher(dispatchTable)) { + printf("Service not started: StartServiceCtrlDispatcher failed.\n" ); + event_log(1000, "Service not started: StartServiceCtrlDispatcher failed"); + } + return 0; +} /* main */ + + +VOID WINAPI service_main(DWORD argc, LPSTR *argv) +{ + DWORD err = 0; + + if (!(sshStatusHandle = RegisterServiceCtrlHandler(SVCNAME, service_ctrl))) + return; + + ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ssStatus.dwServiceSpecificExitCode = 0; + if (send_status(SERVICE_START_PENDING, NO_ERROR, 1000, 1020)) + err = service_run(); + + send_status(SERVICE_STOPPED, err, 0, err ? 1030 : 30); +} /* service_main */ + + +VOID WINAPI service_ctrl(DWORD ctrl_code) +{ /* Handle the requested control code. */ + if (ctrl_code == SERVICE_CONTROL_STOP || ctrl_code == SERVICE_CONTROL_SHUTDOWN) + service_stop(); + else + send_status(ssStatus.dwCurrentState, NO_ERROR, 0, 1040 + ctrl_code); +} /* service_ctrl */ + + +static DWORD service_run(void) +{ + char filename[_MAX_PATH+1]; + char home[_MAX_PATH+1], *p; + char *svc_argv[2] = {filename, "-D"}; + + if (!hMustTerminate) + hMustTerminate = CreateEvent(NULL, FALSE, FALSE, NULL); + set_nt_exit_event(hMustTerminate); + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); + + GetModuleFileName(NULL , filename, _MAX_PATH); + strcpy(home, filename); + if (p = strrchr(home, '\\')) { + *p = 0; + chdir(home); + } + + if (!set_stdfiles()) { + event_log(1010, "stdin|stdout|stderr not created"); + return ERROR_SERVICE_NOT_ACTIVE; + } + + send_status(SERVICE_RUNNING, NO_ERROR, 0, 1060); + event_log(10, "Mixmaster Service started"); + + mix_main(2, svc_argv); + return 0; +} /* service_run */ + + +static void service_stop(void) +{ + send_status(SERVICE_STOP_PENDING, NO_ERROR, 5000, 1070); + if (hMustTerminate) { + SetEvent(hMustTerminate); + if (WaitForSingleObject(hThread, 4500) == WAIT_TIMEOUT) { + if (hThread) { + TerminateThread(hThread, 0); + event_log(1080, "Mixmaster Service terminated forcibly"); + } + } else + event_log(20, "Mixmaster Service stopped"); + CloseHandle(hMustTerminate); + hMustTerminate = NULL; + } else + if (hThread) + TerminateThread(hThread, 0); + if (hThread) + CloseHandle(hThread); + hThread = NULL; + ssStatus.dwCurrentState = SERVICE_STOPPED; +} /* service_stop */ + + +static int set_stdfiles() +{ /* needed for _popen() */ + static DWORD std_handles[]={STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; + FILE *stdfile[]={stdin, stdout, stderr}; + HANDLE hStd; + int fh, stf_fileno; + FILE *fl; + + AllocConsole(); + for (stf_fileno=0; stf_fileno<=2; stf_fileno++) { + hStd = GetStdHandle(std_handles[stf_fileno]); + if (hStd == INVALID_HANDLE_VALUE) + return 0; + fh = _open_osfhandle((long)std_handles[stf_fileno], (stf_fileno ? _O_WRONLY : _O_RDONLY ) | _O_BINARY); + dup2(fh, stf_fileno); + fl = _fdopen(stf_fileno, (stf_fileno ? "wcb" : "rcb" )); + fflush(stdfile[stf_fileno]); + memcpy(stdfile[stf_fileno], fl, sizeof(FILE)); + } + return 1; +} /* set_stdfiles */ + + +static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id) +{ + static DWORD dwCheckPoint = 1; + BOOL ret_val; + + if (not_service) + return TRUE; + + ssStatus.dwCurrentState = current_state; + ssStatus.dwWin32ExitCode = exit_code; + ssStatus.dwWaitHint = wait_hint; + ssStatus.dwControlsAccepted = (current_state == SERVICE_START_PENDING) ? + 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + ssStatus.dwCheckPoint = ((current_state == SERVICE_RUNNING) || (current_state == SERVICE_STOPPED)) ? + 0 : dwCheckPoint++; + + if (!(ret_val = SetServiceStatus(sshStatusHandle, &ssStatus))) + event_log(id, "SetServiceStatus failed"); + return ret_val; +} /* send_status */ + + +static void event_log(DWORD id, char *eventmsg) +{ + HANDLE hEventSource; + char *pStrings[2] = {"", eventmsg}; + + if (not_service) + return; + + if (id > 1000) + pStrings[0] = GetLastErrorText(); + + if (!(hEventSource = RegisterEventSource(NULL, SVCNAME))) + return; + ReportEvent(hEventSource, (WORD)((id < 1000) ? EVENTLOG_SUCCESS : EVENTLOG_ERROR_TYPE), + 0, id, NULL, 2, 0, pStrings, NULL); + DeregisterEventSource(hEventSource); +} /* event_log */ + + +static int run_notservice(int argc, char ** argv) +{ + not_service = TRUE; + return mix_main(argc, argv); +} /* run_notservice */ + + +static int install_service() +{ + SC_HANDLE schService, schSCManager; + char filename[_MAX_PATH+10]; + + if (GetModuleFileName(NULL, filename, _MAX_PATH) == 0) { + printf("Unable to install Mixmaster Service: %s\n", GetLastErrorText()); + return 1; + } + strcat(filename, " --run-svc"); + + if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) { + printf("OpenSCManager failed: %s\n", GetLastErrorText()); + return 1; + } + schService = CreateService(schSCManager, SVCNAME, SVCDISPLAYNAME, + SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, + filename, NULL, NULL, NULL, NULL, NULL); + + if (schService) { + printf("Mixmaster Service installed.\n"); + CloseServiceHandle(schService); + } else { + printf("CreateService failed: %s\n", GetLastErrorText()); + } + + CloseServiceHandle(schSCManager); + return 0; +} /* install_service */ + + +static int remove_service() +{ + SC_HANDLE schService, schSCManager; + int ret_val = 0; + + if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) { + printf("OpenSCManager failed: %s\n", GetLastErrorText()); + return 1; + } + if (!(schService = OpenService(schSCManager, SVCNAME, SERVICE_ALL_ACCESS))) { + CloseServiceHandle(schSCManager); + printf("OpenService failed: %s\n", GetLastErrorText()); + return 1; + } + /* try to stop the service */ + if (ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) { + printf("Stopping Mixmaster Service"); + do { + sleep(1); + printf("."); + QueryServiceStatus(schService, &ssStatus); + } while (ssStatus.dwCurrentState != SERVICE_STOP_PENDING); + + if (ssStatus.dwCurrentState == SERVICE_STOPPED) + printf("\nMixmaster Service stopped.\n"); + else + printf("\n%Mixmaster Service failed to stop.\n"); + } + + /* now remove the service */ + if (!DeleteService(schService)) { + ret_val = 1; + printf("DeleteService failed: %s\n", GetLastErrorText()); + } else + printf("Mixmaster Service removed.\n"); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return ret_val; +} /* remove_service */ + + +static char *GetLastErrorText() +{ + static char error_buf[256]; + DWORD dwRet, err; + LPSTR lpszTemp = NULL; + + dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, err=GetLastError(), LANG_NEUTRAL, (LPSTR)&lpszTemp, 0, NULL); + + /* supplied buffer is not long enough */ + if (!dwRet || (256 < (long)dwRet+14)) + sprintf(error_buf, "Error (0x%x)", err); + else { + lpszTemp[lstrlen(lpszTemp)-2] = '\0'; + /* remove cr and newline character */ + sprintf(error_buf, "%s (0x%x)", lpszTemp, err); + } + + if (lpszTemp) + LocalFree((HLOCAL)lpszTemp); + + return error_buf; +} /* GetLastErrorText */ + +#endif /* WIN32SERVICE */ diff --git a/Src/stats.c b/Src/stats.c @@ -0,0 +1,442 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Remailer statistics + $Id: stats.c 934 2006-06-24 13:40:39Z rabbi $ */ + + +#include "mix3.h" +#include <stdio.h> +#include <string.h> +#include <time.h> + +/* log that a message of type t has been received. Statistics for type 2 + messages are taken from the IDLOG instead of calling this function */ +int stats_log(int t) +{ + FILE *f; + + f = mix_openfile(STATS, "a"); + if (f == NULL) { + errlog(ERRORMSG, "Can't open %s!\n", STATS); + return (-1); + } + lock(f); + fprintf(f, "%d 1 %ld\n", t, (long) time(NULL)); + unlock(f); + fclose(f); + return (0); +} + +/* log the current pool size after sending messages */ +int stats_out(int pool) +{ + FILE *f; + + if (REMAIL == 0) + return (0); /* don't keep statistics for the client */ + + f = mix_openfile(STATS, "a"); + if (f == NULL) { + errlog(ERRORMSG, "Can't open %s!\n", STATS); + return (-1); + } + lock(f); + fprintf(f, "p 1 %d %ld\n", pool, (long) time(NULL)); + unlock(f); + fclose(f); + return (0); +} + +int stats(BUFFER *b) +{ + FILE *s, *f; + char line[LINELEN]; + long now, today, then; + time_t t; + long updated = 0, havestats = 0; + int msgd[7][24], msg[7][80]; + /* 0 .. Unencrypted + * 1 .. Type I PGP + * 2 .. Mix + * + * 3 .. intermediate + * 4 .. final hop mail + * 5 .. final hop news + * 6 .. randhopped (will get counted in intermediate again) + */ + int poold[2][24], pool[2][80]; + int i, num, type, assigned, daysum; + char c; + idlog_t idbuf; + + now = (time(NULL) / (60 * 60) + 1) * 60 * 60; + today = (now / SECONDSPERDAY) * SECONDSPERDAY; + + for (i = 0; i < 24; i++) + msgd[0][i] = msgd[1][i] = msgd[2][i] = msgd[3][i] = msgd[4][i] = msgd[5][i] = msgd[6][i]= poold[0][i] = poold[1][i] = 0; + for (i = 0; i < 80; i++) + msg[0][i] = msg[1][i] = msg[2][i] = msg[3][i] = msg[4][i] = msg[5][i] = msg[6][i] = pool[0][i] = pool[1][i] = 0; + + s = mix_openfile(STATS, "r"); + if (s != NULL) { + lock(s); + fscanf(s, "%ld", &updated); + while (fgets(line, sizeof(line), s) != NULL) { + switch (line[0]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + c = '\0'; + assigned = sscanf(line, "%d %d %ld %c", &type, &num, &then, &c); + daysum = (assigned == 4 && c == 'd'); + + if (now - then < 0 || (daysum && today - then < 0)) + break; /* keep memory consistent even if the time + suddenly goes backwards :) */ + if (now - then < SECONDSPERDAY && !daysum) + msgd[type][(now - then) / (60 * 60)] += num; + else if (today - then < 80 * SECONDSPERDAY) + msg[type][(today - then) / SECONDSPERDAY] += num; + if (havestats == 0 || then < havestats) + havestats = then; + break; + case 'p': + c = '\0'; + assigned = sscanf(line, "p %d %d %ld %c", &num, &i, &then, &c); + daysum = (assigned == 4 && c == 'd'); + + if (now - then < 0 || (daysum && today - then < 0)) + break; + if (now - then < SECONDSPERDAY && !daysum) { + poold[0][(now - then) / (60 * 60)] += num; + poold[1][(now - then) / (60 * 60)] += i; + } else if (today - then < 80 * SECONDSPERDAY) { + pool[0][(today - then) / (24 * 60 * 60)] += num; + pool[1][(today - then) / (24 * 60 * 60)] += i; + } + if (havestats == 0 || then < havestats) + havestats = then; + break; + } + } + unlock(s); + fclose(s); + } + f = mix_openfile(IDLOG, "rb"); + if (f != NULL) { + while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) { + then = idbuf.time; + if (then < updated || now - then < 0) + continue; + if (now - then < SECONDSPERDAY) + msgd[2][(now - then) / (60 * 60)]++; + else if (today - then < 80 * SECONDSPERDAY) + msg[2][(today - then) / SECONDSPERDAY]++; + if (havestats == 0 || then < havestats) + havestats = then; + } + fclose(f); + } + if (havestats == 0) { + if (b != NULL) + errlog(NOTICE, "No statistics available.\n"); + return (-1); + } + s = mix_openfile(STATS, "w"); + if (s == NULL) { + errlog(ERRORMSG, "Can't create %s!\n", STATS); + return (-1); + } + lock(s); + fprintf(s, "%ld\n", (long) time(NULL)); /* time of stats.log update */ + for (i = 0; i < 24; i++) { + for (type = 0; type < 7; type++) + if (msgd[type][i] > 0) + fprintf(s, "%d %d %ld\n", type, msgd[type][i], now - i * 60 * 60); + if (poold[0][i] > 0) + fprintf(s, "p %d %d %ld\n", poold[0][i], poold[1][i], now - i * 60 * 60); + } + for (i = 0; i < 80; i++) { + for (type = 0; type < 7; type++) + if (msg[type][i] > 0) + fprintf(s, "%d %d %ld d\n", type, msg[type][i], + today - i * 24 * 60 * 60); + if (pool[0][i] > 0) + fprintf(s, "p %d %d %ld d\n", pool[0][i], pool[1][i], + today - i * 24 * 60 * 60); + } + unlock(s); + fclose(s); + if (b != NULL) { + struct tm *gt; + + buf_sets(b, "Subject: Statistics for the "); + buf_appends(b, SHORTNAME); + buf_appends(b, " remailer\n\n"); + + buf_appends(b, "Number of messages in the past 24 hours:\n"); + t = now; + gt = gmtime(&t); + for (i = 23; i >= 0; i--) { + buf_appendf(b, " %2dh: ", (24 + gt->tm_hour - i) % 24); + if (MIX) { + if (PGP || UNENCRYPTED) + buf_appends(b, " Mix:"); + buf_appendf(b, "%4d", msgd[2][i]); + } + if (PGP) + buf_appendf(b, " PGP: %4d", msgd[1][i]); + if (UNENCRYPTED) + buf_appendf(b, " Unencrypted:%4d", msgd[0][i]); + if (poold[0][i] > 0) + buf_appendf(b, " [Pool size:%4d]", poold[1][i] / poold[0][i]); +#if 0 + else + buf_appends(b, " [ no remailing ]"); +#endif /* 0 */ + buf_nl(b); + } + if ((today - havestats) / SECONDSPERDAY >= 1) + buf_appends(b, "\nNumber of messages per day:\n"); + for ((i = (today - havestats) / SECONDSPERDAY) > 79 ? 79 : i; + i >= 1; i--) { + t = now - i * SECONDSPERDAY; + gt = gmtime(&t); + strftime(line, LINELEN, "%d %b: ", gt); + buf_appends(b, line); + + if (MIX) { + if (PGP || UNENCRYPTED) + buf_appends(b, " Mix:"); + buf_appendf(b, "%4d", msg[2][i]); + } + if (PGP) + buf_appendf(b, " PGP: %4d", msg[1][i]); + if (UNENCRYPTED) + buf_appendf(b, " Unencrypted:%4d", msg[0][i]); + if (STATSDETAILS) { + buf_appendf(b, " Intermediate:%4d", msg[3][i]); + buf_appendf(b, " Mail:%4d", msg[4][i]); + buf_appendf(b, " Postings:%4d", msg[5][i]); + if (MIDDLEMAN) + buf_appendf(b, " Randhopped:%4d", msg[6][i]); + } + if (pool[0][i] > 0) + buf_appendf(b, " [Pool size:%4d]", pool[1][i] / pool[0][i]); +#if 0 + else + buf_appends(b, " [ no remailing ]"); +#endif /* 0 */ + buf_nl(b); + } + } + return (0); +} + +int conf(BUFFER *out) +{ + FILE *f; + BUFFER *b, *line; + int flag = 0; + REMAILER remailer[MAXREM]; + int pgpkeyid[MAXREM]; + int i, num; + char tmpline[LINELEN]; + + b = buf_new(); + line = buf_new(); + + buf_sets(out, "Subject: Capabilities of the "); + buf_appends(out, SHORTNAME); + buf_appends(out, " remailer\n\n"); + buf_appends(out, remailer_type); + buf_appends(out, VERSION); + buf_nl(out); + + if (MIX + PGP + UNENCRYPTED == 1) + buf_appends(out, "Supported format:"); + else + buf_appends(out, "Supported formats:\n"); + if (MIX) + buf_appends(out, " Mixmaster\n"); + if (PGP) + buf_appends(out, " Cypherpunk with PGP encryption\n"); + if (UNENCRYPTED) + buf_appends(out, " Cypherpunk (unencrypted)\n"); + + buf_appendf(out, "Pool size: %d\n", POOLSIZE); + if (SIZELIMIT) + buf_appendf(out, "Maximum message size: %d kB\n", SIZELIMIT); + + /* display destinations to which delivery is explicitly permitted + when in middleman mode (contents of DESTALLOW file.) */ + + if (MIDDLEMAN) { + f = mix_openfile(DESTALLOW, "r"); + if (f != NULL) { + buf_read(b, f); + fclose(f); + while(buf_getline(b, line) != -1) { + if (line->length > 0 && line->data[0] != '#') { + if (flag == 0) { + buf_appends(out, "In addition to other remailers, this remailer also sends mail to these\n addresses directly:\n"); + flag = 1; + } + buf_appendf(out, " %b\n", line); + } + } + } + } + + flag = 0; + f = mix_openfile(HDRFILTER, "r"); + if (f != NULL) { + buf_read(b, f); + fclose(f); + while(buf_getline(b, line) != -1) + if (line->length > 0 && line->data[0] != '#') { + if (flag == 0) { + buf_appends(out, "The following header lines will be filtered:\n"); + flag = 1; + } + buf_appends(out, " "); + if (line->length > 3 && streq(line->data + line->length - 2, "/q")) { + buf_append(out, line->data, line->length - 1); + buf_appends(out, " => delete message"); + } + else + buf_cat(out, line); + buf_nl(out); + } + buf_free(b); + } + flag = 0; + b = readdestblk( ); + if ( b != NULL ) { + while(buf_getline(b, line) != -1) + if (line->length > 0 && !bufleft(line, "#") && !buffind(line, "@")) { + /* mail addresses are not listed */ + if (flag == 0) { + if (NEWS[0]) + buf_appends(out, + "The following newsgroups/domains are blocked:\n"); + else + buf_appends(out, "The following domains are blocked:\n"); + flag = 1; + } + buf_appendf(out, " %b\n", line); + } + if (flag == 0 && NEWS[0]) + buf_appends(out, "Note that other newsgroups may be unavailable at the remailer's news server.\n"); + } + + buf_nl(out); + conf_premail(out); + + if (LISTSUPPORTED) { + /* SUPPORTED CPUNK (TYPE I) REMAILERS + * 0xDC7532F9 "Heex Remailer <remailer@xmailer.ods.org>" + * 0x759ED311 "znar <ka5tkn@cox-internet.com>" + * + * SUPPORTED MIXMASTER (TYPE II) REMAILERS + * aarg remailer@aarg.net 475f3f9fe8da22896c10082695a92c2d 2.9b33 C + * anon mixmaster@anon.978.org 7384ba1eec585bfd7d2b0e9b307f0b1d 2.9b36 MCNm + */ + + buf_nl(out); +#ifdef USE_PGP + if (PGP) { + buf_appends(out, "SUPPORTED CPUNK (TYPE I) REMAILERS\n"); + num = t1_rlist(remailer, NULL); + pgp_rkeylist(remailer, pgpkeyid, num); + for (i=1; i<=num; i++) { + if (remailer[i].flags.pgp) { + snprintf(tmpline, LINELEN, "0x%08X \"%s <%s>\"\n", pgpkeyid[i], remailer[i].name, remailer[i].addr); + tmpline[LINELEN-1] = '\0'; + buf_appends(out, tmpline); + } + } + buf_nl(out); + } +#endif /* USE_PGP */ + if (MIX) { + buf_appends(out, "SUPPORTED MIXMASTER (TYPE II) REMAILERS\n"); + prepare_type2list(out); + buf_nl(out); + } + } + + + if ( b ) buf_free(b); + buf_free(line); + return (0); +} + +void conf_premail(BUFFER *out) +{ + buf_appends(out, "$remailer{\""); + buf_appends(out, SHORTNAME); + buf_appends(out, "\"} = \"<"); + buf_appends(out, REMAILERADDR); + buf_appendc(out, '>'); + if (PGP || UNENCRYPTED) + buf_appends(out, " cpunk max"); + if (MIX) + buf_appends(out, " mix"); + if (MIDDLEMAN) + buf_appends(out, " middle"); + if (PGP) + buf_appends(out, " pgp"); + if (PGP && !UNENCRYPTED) + buf_appends(out, " pgponly"); + if (PGP && REPGP) { + if (REMIX == 1) + buf_appends(out, " repgp"); + else + buf_appends(out, " repgp2"); + } + if (REMIX == 1) + buf_appends(out, " remix"); + else if (REMIX) + buf_appends(out, " remix2"); + if (PGP || UNENCRYPTED) + buf_appends(out, " latent hash cut test"); + if (PGP) { +#ifdef USE_IDEA + buf_appends(out, " ek"); +#endif /* USE_IDEA */ + buf_appends(out, " ekx"); + } +#ifdef USE_IDEA + buf_appends(out, " esub"); +#endif /* USE_IDEA */ +#if 0 /* obsolete */ +#ifdef USE_NSUB + buf_appends(out, " nsub"); +#else /* end of USE_NSUB */ + buf_appends(out, " ksub"); +#endif /* else if not USE_NSUB */ +#endif /* 0 */ + if (INFLATEMAX) + buf_appendf(out, " inflt%d", INFLATEMAX); + if (MAXRANDHOPS) + buf_appendf(out, " rhop%d", MAXRANDHOPS); + if (POOLSIZE >= 5) + buf_appends(out, " reord"); + if (NEWS[0]) + buf_appends(out, " post"); + if (SIZELIMIT) + buf_appendf(out, " klen%d", SIZELIMIT); + if (EXTFLAGS[0]) + buf_appendf(out, " %s", EXTFLAGS); + buf_appends(out, "\";\n"); +} diff --git a/Src/tests/test-parse_yearmonthday.c b/Src/tests/test-parse_yearmonthday.c @@ -0,0 +1,59 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#define LINELEN 128 + +time_t parse_yearmonthday(char* str) +{ + time_t date; + int day, month, year; + + if (sscanf( str, "%d-%d-%d", &year, &month, &day) == 3 ) { + struct tm timestruct; + char *tz; + + tz = getenv("TZ"); +#ifdef HAVE_SETENV + setenv("TZ", "GMT", 1); +#else /* end of HAVE_SETENV */ + putenv("TZ=GMT"); +#endif /* else if not HAVE_SETENV */ + tzset(); + memset(&timestruct, 0, sizeof(timestruct)); + timestruct.tm_mday = day; + timestruct.tm_mon = month - 1; + timestruct.tm_year = year - 1900; + date = mktime(&timestruct); +#ifdef HAVE_SETENV + if (tz) + setenv("TZ", tz, 1); + else + unsetenv("TZ"); +#else /* end of HAVE_SETENV */ + if (tz) { + char envstr[LINELEN]; + snprintf(envstr, LINELEN, "TZ=%s", tz); + putenv(envstr); + } else + putenv("TZ="); +#endif /* else if not HAVE_SETENV */ + tzset(); + return date; + } else + return -1; +} + +int main() +{ + int t; + + t = parse_yearmonthday("2003-04-02"); + if (t == 1049241600) { + printf("OK.\n"); + exit(0); + } else { + printf("Failed.\n"); + exit(1); + } +} diff --git a/Src/util.c b/Src/util.c @@ -0,0 +1,704 @@ +/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. + + Mixmaster may be redistributed and modified under certain conditions. + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the file COPYRIGHT for + details. + + Utility functions + $Id: util.c 934 2006-06-24 13:40:39Z rabbi $ */ + +#include "mix3.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef POSIX +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <sys/file.h> +#include <termios.h> +#else /* end of POSIX */ +#include <io.h> +#endif /* else if not POSIX */ +#ifdef HAVE_GETKEY +#include <pc.h> +#endif /* HAVE_GETKEY */ +#include <assert.h> + +/** string comparison functions. return 1 on match, 0 otherwise ********/ + +int strileft(const char *string, const char *keyword) +{ + register unsigned int i; + + for (i = 0; keyword[i] != '\0'; i++) + if (tolower(string[i]) != tolower(keyword[i])) + return 0; + return 1; +} + +int striright(const char *string, const char *keyword) +{ + int l; + l = strlen(string) - strlen(keyword); + return (l >= 0 ? strieq(string + l, keyword) : -1); +} + +int strleft(const char *string, const char *keyword) +{ + register unsigned int i; + + for (i = 0; keyword[i] != '\0'; i++) + if (string[i] != keyword[i]) + return 0; + return 1; +} + +int strifind(const char *string, const char *keyword) +{ + register unsigned int i, j; + char k; + + k = tolower(keyword[0]); + for (i = 0; string[i] != '\0'; i++) { + if (tolower(string[i]) == k) { + for (j = 1; keyword[j] != '\0'; j++) + if (tolower(string[i + j]) != tolower(keyword[j])) + goto next; + return 1; + } + next: + ; + } + return 0; +} + +int strieq(const char *s1, const char *s2) +{ + register unsigned int i = 0; + + do + if (tolower(s1[i]) != tolower(s2[i])) + return 0; + while (s1[i++] != '\0') ; + return 1; +} + +int streq(const char *a, const char *b) +{ + return (strcmp(a, b) == 0); +} + +int strfind(const char *a, const char *keyword) +{ + return (strstr(a, keyword) != NULL); +} + +void strcatn(char *dest, const char *src, int n) +{ + int l; + l = strlen(dest); + if (l < n) + strncpy(dest + l, src, n - l - 1); + dest[n-1] = '\0'; +} + +/** files **************************************************************/ + +int mixfile(char *path, const char *name) +{ + char *h; + assert(path != NULL && name != NULL); + +#ifdef POSIX + if (name[0] == '~' && name[1] == DIRSEP && (h = getenv("HOME")) != NULL) { + strncpy(path, h, PATHMAX); + path[PATHMAX-1] = '\0'; + strcatn(path, name + 1, PATHMAX); + } else +#endif /* POSIX */ + if (name[0] == DIRSEP || (isalpha(name[0]) && name[1] == ':') || MIXDIR == NULL) { + strncpy(path, name, PATHMAX); + path[PATHMAX-1] = '\0'; + } else { + strncpy(path, MIXDIR, PATHMAX); + path[PATHMAX-1] = '\0'; + strcatn(path, name, PATHMAX); + } + return (0); +} + +FILE *mix_openfile(const char *name, const char *a) +{ + char path[PATHMAX]; + + mixfile(path, name); + return (fopen(path, a)); +} + +FILE *openpipe(const char *prog) +{ + FILE *p = NULL; + +#ifdef POSIX + p = popen(prog, "w"); +#endif /* POSIX */ +#ifdef _MSC + p = _popen(prog, "w"); +#endif /* _MSC */ + + if (p == NULL) + errlog(ERRORMSG, "Unable to open pipe to %s\n", prog); + return p; +} + +int +file_to_out(const char *filename) +{ + int len; + FILE *fp; + char chunk[1024]; + + if ((fp = mix_openfile(filename, "r")) == NULL) + return -1; + while ((len = fread(chunk, 1, sizeof(chunk), fp)) > 0) + { + fwrite(chunk, 1, len, stdout); + } + fclose (fp); + return (len == 0 ? 0 : (-1)); +} + +int closepipe(FILE *p) +{ +#ifdef POSIX + return (pclose(p)); +#elif defined(_MSC) /* end of POSIX */ + return (_pclose(p)); +#else /* end of defined(_MSC) */ + return -1; +#endif /* else if not defined(_MSC), POSIX */ +} + +/** Base 64 encoding ****************************************************/ + +static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static byte asctobin[] = +{ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0076, 0x80, 0x80, 0x80, 0077, + 0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073, + 0074, 0075, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0000, 0001, 0002, 0003, 0004, 0005, 0006, + 0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016, + 0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026, + 0027, 0030, 0031, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0032, 0033, 0034, 0035, 0036, 0037, 0040, + 0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050, + 0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060, + 0061, 0062, 0063, 0x80, 0x80, 0x80, 0x80, 0x80, + + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 +}; + +void id_encode(byte id[], byte *s) +{ + sprintf + (s, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], + id[10], id[11], id[12], id[13], id[14], id[15]); +} + +void id_decode(byte *s, byte id[]) +{ + int i, x[16]; + + sscanf + (s, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + x, x + 1, x + 2, x + 3, x + 4, x + 5, x + 6, x + 7, x + 8, + x + 9, x + 10, x + 11, x + 12, x + 13, x + 14, x + 15); + for (i = 0; i < 16; i++) + id[i] = x[i]; +} + +int encode(BUFFER *in, int linelen) +{ + byte *b, *e; + int i, l, m; + unsigned long u; + BUFFER *out; + + out = buf_new(); + + l = in->length; + if (l % 3 != 0) + l += 2; + l = l / 3 * 4; + + if (linelen) { + l += l / linelen + (l % linelen > 0 ? 1 : 0); + } + linelen /= 4; /* blocks of 4 characters */ + + buf_prepare(out, l); + + b = in->data; + e = out->data; + m = in->length - 2; + for (i = 0, l = 0; i < m; i += 3) { + u = ((unsigned long) b[i] << 16) | ((unsigned long) b[i + 1] << 8) | + b[i + 2]; + *e++ = bintoasc[(u >> 18) & 0x3f]; + *e++ = bintoasc[(u >> 12) & 0x3f]; + *e++ = bintoasc[(u >> 6) & 0x3f]; + *e++ = bintoasc[u & 0x3f]; + if (linelen && ++l >= linelen) { + l = 0; + *e++ = '\n'; + } + } + if (i < in->length) { + *e++ = bintoasc[b[i] >> 2]; + *e++ = bintoasc[((b[i] << 4) & 0x30) | ((b[i + 1] >> 4) & 0x0f)]; + if (i + 1 == in->length) + *e++ = '='; + else + *e++ = bintoasc[((b[i + 1] << 2) & 0x3c) | ((b[i + 2] >> 6) & 0x03)]; + *e++ = '='; + ++l; + } + if (linelen && l != 0) + *e++ = '\n'; + *e = '\0'; + + assert(out->data + out->length == e); + buf_move(in, out); + buf_free(out); + return (0); +} + +int decode(BUFFER *in, BUFFER *out) +{ + int err = 0; + register byte c0 = 0, c1 = 0, c2 = 0, c3 = 0; + register byte *a, *d, *end; + int tempbuf = 0; + int i; + + if (in == out) { + out = buf_new(); + tempbuf = 1; + } + buf_prepare(out, 3 * (in->length - in->ptr) / 4); + + a = in->data + in->ptr; + end = in->data + in->length - 3; + d = out->data; + i = 0; + + while (a < end) { + if ((c0 = asctobin[a[0]]) & 0x80 || + (c1 = asctobin[a[1]]) & 0x80 || + (c2 = asctobin[a[2]]) & 0x80 || + (c3 = asctobin[a[3]]) & 0x80) { + if (a[0] == '\n') { /* ignore newline */ + a++; + continue; + } else if (a[0] == '\r' && a[1] == '\n') { /* ignore crlf */ + a += 2; + continue; + } else if (a[0] == '=' && a[1] == '4' && a[2] == '6' && !(asctobin[a[5]] & 0x80) ) { + a += 2; /* '=46' at the left of a line really is 'F' */ + *a = 'F'; /* fix in memory ... */ + continue; + } else if (a[2] == '=' || a[3] == '=') { + if (a[0] & 0x80 || (c0 = asctobin[a[0]]) & 0x80 || + a[1] & 0x80 || (c1 = asctobin[a[1]]) & 0x80) + err = -1; + else if (a[2] == '=') + c2 = 0, i += 1; + else if (a[2] & 0x80 || (c2 = asctobin[a[2]]) & 0x80) + err = -1; + else + i += 2; + if (err == 0) { + /* read the correct final block */ + *d++ = (byte) ((c0 << 2) | (c1 >> 4)); + *d++ = (byte) ((c1 << 4) | (c2 >> 2)); + if (a[3] != '=') + *d++ = (byte) ((c2 << 6)); +#if 1 + if (a + 4 < in->data + in->length) { + a += 4; + continue; /* support Mixmaster 2.0.3 encoding */ + } +#endif /* 1 */ + break; + } + } + err = -1; + break; + } + a += 4; + + *d++ = (byte) ((c0 << 2) | (c1 >> 4)); + *d++ = (byte) ((c1 << 4) | (c2 >> 2)); + *d++ = (byte) ((c2 << 6) | c3); + i += 3; + } + + in->ptr = a - in->data; + + assert(i <= out->length); + out->length = i; + + if (tempbuf) { + buf_move(in, out); + buf_free(out); + } + return (err); +} + +LOCK *lockfile(char *filename) +{ + LOCK *l; + char name[LINELEN]; + + strcpy(name, "lck"); + if (strchr(filename, DIRSEP)) + strcatn(name, strrchr(filename, DIRSEP), LINELEN); + else + strcatn(name, filename, LINELEN); + l = malloc(sizeof(LOCK)); + + l->name = malloc(PATHMAX); + mixfile(l->name, name); + l->f = mix_openfile(l->name, "w+"); + if (l->f) + lock(l->f); + return (l); +} + +int unlockfile(LOCK *l) +{ + if (l->f) { + unlock(l->f); + fclose(l->f); + } + unlink(l->name); + free(l->name); + free(l); + return (0); +} + +int lock(FILE *f) +{ +#ifndef WIN32 + struct flock lockstruct; + + lockstruct.l_type = F_WRLCK; + lockstruct.l_whence = 0; + lockstruct.l_start = 0; + lockstruct.l_len = 0; + return (fcntl(fileno(f), F_SETLKW, &lockstruct)); +#else /* end of WIN32 */ + return (0); +#endif /* else if not WIN32 */ +} + +int unlock(FILE *f) +{ +#ifndef WIN32 + + struct flock lockstruct; + + lockstruct.l_type = F_UNLCK; + lockstruct.l_whence = 0; + lockstruct.l_start = 0; + lockstruct.l_len = 0; + return (fcntl(fileno(f), F_SETLKW, &lockstruct)); +#else /* end of not WIN32 */ + return (0); +#endif /* else if WIN32 */ +} + +/* get passphrase ******************************************************/ + +static int getuserpass(BUFFER *b, int mode) +{ + char p[LINELEN]; + int fd; + int n; + +#ifdef HAVE_TERMIOS + struct termios attr; + +#endif /* HAVE_TERMIOS */ + + if (mode == 0) + fprintf(stderr, "enter passphrase: "); + else + fprintf(stderr, "re-enter passphrase: "); + fflush(stderr); +#ifndef UNIX +#ifdef HAVE_GETKEY + for (n = 0; p[n] != '\n' && n < LINELEN; n++) { + p[n] = getkey(); + } + p[n] = 0; +#else /* end of HAVE_GETKEY */ + scanf("%127s", p); +#endif /* else if not HAVE_GETKEY */ +#else /* end of not UNIX */ + fd = open("/dev/tty", O_RDONLY); + if (tcgetattr(fd, &attr) != 0) + return (-1); + attr.c_lflag &= ~ECHO; + attr.c_lflag |= ICANON; + if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) + return (-1); + + n = read(fd, p, LINELEN); + + attr.c_lflag |= ECHO; + if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) + return (-1); + + close(fd); + fprintf(stderr, "\n"); + p[n - 1] = 0; +#endif /* else if UNIX */ + if (mode == 0) + buf_appends(b, p); + else + return (bufeq(b, p)); + return (0); +} + +static BUFFER *userpass = NULL; + +int user_pass(BUFFER *key) +{ + if (userpass == NULL) { + userpass = buf_new(); + userpass->sensitive = 1; + if (getenv("MIXPASS")) + buf_sets(userpass, getenv("MIXPASS")); + else if (menu_getuserpass(userpass, 0) == -1) + getuserpass(userpass, 0); + } + buf_set(key, userpass); + key->sensitive = 1; + return (0); +} + +int user_confirmpass(BUFFER *key) +{ + int ok; + + ok = menu_getuserpass(key, 1); + if (ok == -1) + ok = getuserpass(key, 1); + return (ok); +} + +void user_delpass(void) +{ + if (userpass) + buf_free(userpass); + userpass = NULL; +} + +int write_pidfile(char *pidfile) +{ + int err = 0; +#ifdef POSIX + FILE *f; + char host[LINELEN], myhostname[LINELEN]; + int pid, mypid; + int assigned; + + mypid = getpid(); + gethostname(myhostname, LINELEN); + myhostname[LINELEN-1] = '\0'; + + f = mix_openfile(pidfile, "r+"); + if (f != NULL) { + assert(LINELEN > 71); + assigned = fscanf(f, "%d %70s", &pid, host); + if (assigned == 2) { + if (strcmp(host, myhostname) == 0) { + if (kill (pid, 0) == -1) { + if (errno == ESRCH) { + fprintf(stderr, "Rewriting stale pid file.\n"); + rewind(f); + ftruncate(fileno(f), 0); + fprintf(f, "%d %s\n", mypid, myhostname); + } else { + fprintf(stderr, "Pid file exists and process still running.\n"); + err = -1; + } + } else { + fprintf(stderr, "Pid file exists and process still running.\n"); + err = -1; + } + } else { + /* Pid file was written on another host, fail */ + fprintf(stderr, "Pid file exists and was created on another host (%s).\n", host); + err = -1; + } + } else { + fprintf(stderr, "Pid file exists and and could not be parsed.\n"); + err = -1; + } + } else { + if (errno == ENOENT) { + f = mix_openfile(pidfile, "w+"); + if (f != NULL) { + fprintf(f, "%d %s\n", mypid, myhostname); + } else { + fprintf(stderr, "Could not open pidfile for writing: %s\n", strerror(errno)); + err = -1; + } + } else { + fprintf(stderr, "Could not open pidfile for readwrite: %s\n", strerror(errno)); + err = -1; + }; + } + if(f) + fclose(f); +#endif /* POSIX */ + return (err); +} + +int clear_pidfile(char *pidfile) +{ +#ifdef POSIX + char path[PATHMAX]; + + mixfile(path, pidfile); + return (unlink(path)); +#else /* end of POSIX */ + return (0); +#endif /* else if not POSIX */ +} + +time_t parse_yearmonthday(char* str) +{ + time_t date; + int day, month, year; + + if (sscanf( str, "%d-%d-%d", &year, &month, &day) == 3 ) { + struct tm timestruct; + char *tz; + + tz = getenv("TZ"); +#ifdef HAVE_SETENV + setenv("TZ", "GMT", 1); +#else /* end of HAVE_SETENV */ + putenv("TZ=GMT"); +#endif /* else if not HAVE_SETENV */ + tzset(); + memset(&timestruct, 0, sizeof(timestruct)); + timestruct.tm_mday = day; + timestruct.tm_mon = month - 1; + timestruct.tm_year = year - 1900; + date = mktime(&timestruct); +#ifdef HAVE_SETENV + if (tz) + setenv("TZ", tz, 1); + else + unsetenv("TZ"); +#else /* end of HAVE_SETENV */ + if (tz) { + char envstr[LINELEN]; + snprintf(envstr, LINELEN, "TZ=%s", tz); + putenv(envstr); + } else + putenv("TZ="); +#endif /* else if not HAVE_SETENV */ + tzset(); + return date; + } else + return -1; +} + +/* functions missing on some systems *************************************/ + +#ifdef __RSXNT__ +int fileno(FILE *f) +{ + return (f->_handle); +} + +#endif /* __RSXNT__ */ + +#ifdef _MSC /* Visual C lacks dirent */ + +DIR *opendir(const char *name) +{ + DIR *dir; + WIN32_FIND_DATA d; + char path[PATHMAX]; + + dir = malloc(sizeof(HANDLE)); + + sprintf(path, "%s%c*", name, DIRSEP); + *dir = FindFirstFile(path, &d); + /* first file found is "." -- can be safely ignored here */ + + if (*dir == INVALID_HANDLE_VALUE) { + free(dir); + return (NULL); + } else + return (dir); +} + +struct dirent e; +struct dirent *readdir(DIR *dir) +{ + WIN32_FIND_DATA d; + int ok; + + ok = FindNextFile(*dir, &d); + if (ok) { + strncpy(e.d_name, d.cFileName, PATHMAX); + return (&e); + } else + return (NULL); +} + +int closedir(DIR *dir) +{ + if (dir) { + FindClose(*dir); + free(dir); + return (0); + } + return (-1); +} + +#endif /* _MSC */ diff --git a/Src/version.h b/Src/version.h @@ -0,0 +1 @@ +#define VERSION "3.0" diff --git a/THANKS b/THANKS @@ -0,0 +1,102 @@ +Mixmaster Version 3.0 + +As I write this, Mixmaster is over a decade old. This incarnation of the +codebase was begun almost exactly 10 years ago, and the idea conceived +nearly half that again. Despite many changes in the social, political, +legal, and technological landscape, Mixmaster has continuously provided +anonymity services to those who need it throughout this time. + +Many people have helped with the development of Mixmaster during its +long history. Lance Cottrell wrote the original 1.x and 2.0.x versions. +Ulf Möller contributed significantly to the 2.0.x versions, and wrote +the core code for 2.9 from scratch. I'd like to give special thanks to +Peter Palfrader, Colin Tuckley, and Steve Crook. As the core members of +the Mixmaster development team, without their tireless efforts, this +project would not be sustainable. + +Additionally, I would like to honor the memory of a former valued member +of the development team, Janis Jagars, whose work made this release +possible, though sadly, he passed away tragically before it was +completed. "Disastry", you are missed. + +Mixmaster uses Jean-loup Gailly and Mark Adler's compression library zlib, +Philip Hazel's Perl Compatible Regular Expressions library, the ncurses +library (originally written by Zeyd Ben-Halim and Eric Raymond), and +OpenSSL (based on work by Eric Young and Tim Hudson.) + +I have compiled below a partial list of people who have contributed to +Mixmaster's success, through suggestions, bug reports, patches, or other +contributions. Please report any omissions to me. + +There have been numerous anonymous contributions to this project as well. +While we obviously can't thank the contributor(s) by name, they are still +very much appreciated. + +Thanks also to all the remailer operators, who give their time and service +(and perform what is too often a thankless job) to ensure that our right +to anonymous speech is preserved. + +Finally, thank you to my colleagues at COSIC, and my advisors, Prof. +Bart Preneel and Prof. David Chaum, for their support of my work on this +project. + + +Len Sassaman +03 March 2008 +Leuven, Belgium +http://homes.esat.kuleuven.be/~lsassama/ + + +Credits: + +Antonomasia +Erik Arneson +Adam Back +Kevin Bennett +Gerd Beuster +Jim Castleberry +cmeclax +Bram Cohen +Steve Crook +Lance Cottrell +Richard Christman +Todd Cutter +Dingo Admin +Andy Dustman +Sami Farin +John B. Fleming +Bryan Fordham +Laurent Fousse +Ron Fritz +goblin +Mark Grant +Lucky Green +Mark Hahn +Janis Jagars +Richard Johnson +Alex de Joode +Katherine +Johannes Kroeger +Hauke Lampe +Ben Laurie +Patrick J. LoPresti +L. McCarthy +Medusa +Christian Mock +Bodo Möller +Ulf Möller +noise +Bill O'Hanlon +Peter Palfrader +John A. Perry +Scott Renfro +RProcess +Len Sassaman +Senshi-Admin +Markus Stöger +Nikolay Sturm +Trek +Rodney Thayer +Colin Tuckley +André M. VanKlaveren +Michael Young diff --git a/TODO b/TODO @@ -0,0 +1,77 @@ +Items that need to be completed before the next MAIN release: + +- revert renaming of conf files for WIN32. + +Items to watch: + +- Hunt and kill bug in Mixmaster causing echolot pings to be turned + into permanent t* files. + [This is a pesky one. Changing the .forward pipe to go through + truss first 'fixes' it. Grr. --rabbi] + +Items for 3.0.x: +- doallow() should check more than one email address in a line +- Automatically fetch pinger list and stats during installation process +- destblk request confirmation (patch # 873498) + + perhaps we should phase this out in favor of a distributed RAB? +- general bug fixes that do not break backward compatibility + +Items for 3.1.x +- Full WIN32 support. + - Sane randomness handling + - Resolve crash when running with --post + - Resolve crash when config contains "SENDMAIL outfile" + - Confirm operation as a WIN32 service + - Test on Vista. +- Include a formal win32 binary release, complete with docs. +- Integrate RAB support -- automatic downloading similar to stats. +- Introduce hashed RAB handling where mail recipients are hashed and + compared against a downloaded rab.hash file. This solves the issue + of publishing a plain-text list of email addresses. + + We might want to salt these hashes but the salt would have to be + known to remops. +- Hashcash support? + +Items for 3.5: + +- binomial mix implementation +- RGB dummies +- native echolot +- Regroup-and-Go? + +Packaging: +- Modify release tarball generation script to build the .tab.c file from + parsedate.y, so we don't end up requiring bison on every system that + wants to build mixmaster (rabbi) +- rpm -- dybbuk +- Windows build instructions/files (zax) +- provide a packaged Windows build to be used with QuickSilver +- Macintosh OS/X support (rabbi) +- Update Install script to put files in global system locations if + invoked by root. Also update to be smart about AES support. + (dybbuk said he would do this, but status is unclear.) + +Wishlist: +- permit CRAM-MD5 SMTP AUTH in addition to LOGIN. n/a (patch welcome) +- do full regression tests on as many platforms possible + - list only these platforms as supported + - test on Solaris 9 on SPARC. +- saner usage of /dev/[u]random is required -- throw warning when not in + daemon mode (patch 873497 -- needs work) +- clean up documentation and tarball contents + + reorganize directory structure +- AES support -- requires OpenSSL 0.9.7 dybbuk + + +Abandoned/Deferred: +D Remove OpenSSL version checks. Maybe print a message stating the + supported versions, and leave it up to the user? +D allow for verification of clearsigned OpenPGP messages disastry +D honor key preferences when encrypting to multiple keys ulf/disastry (n/a) +D further mpgp testing of AES/MDC packet support ulf +D make mpgp friendlier +D COMMENT entire existing codebase! (HAHA) +D support for Borland compiler on Windows. + D I'ld even go so far as drop Visual C (or whatever we're supporting at + the moment) and require gcc with Cygwin to build it. But only if this + results in a Binary that runs without additional DLLs. (Weasel) diff --git a/conf/abuse.txt.in b/conf/abuse.txt.in @@ -0,0 +1,99 @@ +Thank you for contacting the Abuse Complaint Administrator +of the %RMN. + +We sincerely apologize for any inconvenience that you may have +experienced as a result of inappropriate use of this system by a +particular individual. + +The purpose of this anonymous remailer is to permit individuals +including crime victims, domestic violence victims, persons in recovery, +and others, such as those living under oppressive regimes, to +communicate confidentially in a manner that ensures their privacy under +even the most adverse conditions. Unfortunately, there will always be a +very small percentage of individuals that choose to abuse the anonymity +that this and similar systems worldwide afford to insult, harass, or +send otherwise unwelcome email. + +The operator of this remailer does not condone such messages, or their +content, in any way. + +Just as the Post Office is unable to prevent abuse of the mail system as +long as there are public mailboxes into which a person can drop a letter +without including a return address, this remailer cannot preemptively +prevent irresponsible individuals from using this system to send +inappropriate messages. However, unlike the Post Office, this remailer +enables you to assure that you will not be inconvenienced by users of +this remailer in the future. +========================================================================= + +How to block your email address from receiving email from the +%RMN: + +To block the users of this remailer from sending email to your address, +please send a message to <%RMA> +containing the line + +DESTINATION-BLOCK + +anywhere in the body text of the email. You can simply reply to this +message using your email program and send back this entire message for +your current email address to be permanently blocked from users of the +%RMN. + +If you wish to block additional email addresses that you may use from +receiving email though this remailer, please reply to this email with a +line similar to + +DESTINATION-BLOCK my_other_email_address@my_domain.com + +You must include one such line per email address that you wish to block. +You can include more than one line in your reply. +========================================================================== + +How to block an entire domain from receiving email from the +%RMN: + +If you are the legitimate root administrator or postmaster of a domain, +you may request that all email addresses served by you domain are +blocked from receiving email from this remailer . To place this block, +please send the following line as "root" or "postmaster" to +<%RMA> in the body text of your email: + +DESTINATION-BLOCK @domain_to_be_blocked.com + +========================================================================== +Note that there are similar remailer systems in operation on the +Internet that not affiliated with the %RMN. + +Since the administrator of this remailer has no influence on those other +systems and is likely to be unaware of many of these other systems, a +destination block that you may choose to request by replying to this +email is only effective for the %RMN, +not for similar systems that may exist on the Internet. + +========================================================================== + +How to obtain the name of the sender of an email that you received +though this remailer: + +This remailer uses the Mixmaster anonymous remailer software. The +Mixmaster software has been carefully designed to withstand attack by +even the most severe regimes in which torture is a common means of +inquiry and basic human rights are nonexistent. As such, it is +impossible to determine the original sender of an email that has passed +through this system. + +The administrator of this system is technically unable to determine the +original sender of a message that has passed through this remailer, no +matter how much the administrator may desire to do so, even if the +administrator were ordered to do so by legal or extra-legal means. We +regret any inconvenience this necessary safety protection may cause to +some recipients of undesired emails. + +Remember: you can prevent future unwanted emails sent to you via this +remailer by simply replying to this message. + +Sincerely, + +-- The %RMN Administrator + diff --git a/conf/adminkey.txt b/conf/adminkey.txt @@ -0,0 +1 @@ +Remailer Administrator's key goes here. diff --git a/conf/blocked.txt.in b/conf/blocked.txt.in @@ -0,0 +1,20 @@ +Subject: %RMN Blocking Confirmation +Reply-To: Abuse Complaint Administrator <%CA> + +Thank you for contacting the Abuse Complaint Administrator of the +%RMN. +The administrator has processed your request to not receive emails from +this anonymous remailer. This remailer will no longer send emails to the +email address(es) for which you requested a block. Note that due to fact +that Internet email can arrive at the destination out-of-sequence, it is +possible, though unlikely, that you may receive emails from this +remailer that were sent prior to your blocking request, but have not yet +been received by you. + +We again wish to apologize for any inconvenience that may have been +caused to you. + +Sincerely, + +-- The %RMN Administrator + diff --git a/conf/dest.alw b/conf/dest.alw @@ -0,0 +1,41 @@ +## List of addresses to which Mixmaster will deliver, even in middleman mode +## Beware: substring matches +## +## $Id: dest.alw,v 1.3 2003/09/03 16:51:12 packbart Exp $ + + +## +## allowed destinations +## + +## Allows mail to *@example.com +#/@example\.com$/ + +## Matches *myaddress@example.net* +#myaddress@example.net + +## Allows direct posts to alt.test and alt.anonymous.messages +## (only mix posts unless mail2news@ is whitelisted, too) +#/^Newsgroups: +(alt\.test|alt\.anonymous\.messages)$/ + + +## +## nymservers +## + +/@nym\.alias\.net$/ +/@hod\.aarg\.net$/ +/@blackhole\.riot\.eu\.org$/ +/@nym\.cryptofortress\.com$/ +/@nym\.xganon\.com$/ +/@rodent\.frell\.eu\.org$/ + +## +## presumably dead nymservers +## + +#/@redneck\.gacracker\.org$/ +#/@anon\.nymserver\.com$/ +#/@mailanon\.com$/ +/@alias\.cyberpass\.net$/ + diff --git a/conf/dest.blk b/conf/dest.blk @@ -0,0 +1,2 @@ +president@whitehouse.gov +majordomo@ diff --git a/conf/end.hlp b/conf/end.hlp @@ -0,0 +1,36 @@ +Abuse Policy: + +Unfortunately, there will always be a very small percentage of +individuals that choose to abuse the anonymity that this and similar +systems worldwide afford to send otherwise unwelcome email. The +%RMN does not condone such messages, or their content, +in any way. + +Just as the Post Office is unable to prevent abuse of the mail system as +long as there are public mailboxes into which a person can drop a letter +without including a return address, the %RMN cannot preemptively +prevent irresponsible individuals from using this system to send +inappropriate messages. However, unlike the Post Office, this remailer +enables you to assure that you will not be inconvenienced by users of +this remailer in the future. + +To block the users of this remailer from sending email to your address, +please send a message to <%RMA> +containing the line + +DESTINATION-BLOCK + +anywhere in the body text of the email. You can simply reply to this +message using your email program and send back this entire message for +your current email address to be permanently blocked from users of the +%RMN. + +For additional information on this remailer's abuse policy, instructions +on how to block more than one email address, and to reach the +%RMN operator, please send +email to <%CA>. + +Thank you for your interest in secure and private communications, + +-- The %RMN Administrator + diff --git a/conf/header.blk b/conf/header.blk @@ -0,0 +1,22 @@ +# Header lines to be filtered out. + +/^From:/ +/^Sender:/ +/^X-Sender:/ +/^Resent-/ +/^Approved:/ +/^Errors-To:/ +/^Message-ID:/ +/^Comments: Authenticated sender is/ +/^Path:/ +/^Received:/ + +/^Control: rmgroup/q +/^Control: newgroup/q +/^Control: sendsys/q +/^Control: checkgroups/q +/^Control: version/q + +# Don't allow excessive crossposting: +/^Newsgroups:.*,.*,.*,.*,.*,/q + diff --git a/conf/intro.hlp b/conf/intro.hlp @@ -0,0 +1,15 @@ +Subject: Your help request for the %RMN +Reply-To: <%RMA> + +This message is sent to you in response to an email that you sent to +the %RMN. +This automated reply was trigged by the subject "remailer-help" +contained in your email. If you did not send such an email, please +ignore this message. + +This remailer is a free service that allows individuals including crime +victims, domestic violence victims, persons in recovery, and others, +such as those living under oppressive regimes, to communicate +confidentially in a manner that ensures their privacy under even the +most adverse conditions. + diff --git a/conf/mix.cfg b/conf/mix.cfg @@ -0,0 +1,14 @@ +######################## Client configuration: ########################## +REMAIL n + +#NAME your realname +#ADDRESS user@host + +SENDPOOLTIME 0h +CHAIN *,*,*,* +NUMCOPIES 1 +DISTANCE 2 +MINREL 98 +RELFINAL 99 +MAXLAT 36h +MINLAT 5m diff --git a/conf/mix.cfg.ex b/conf/mix.cfg.ex @@ -0,0 +1,192 @@ +## mix.cfg - Mixmaster configuration file +## see mixmaster(1) for a description +## +## All paths relative to compile-time defined SPOOL (default: ~/Mix) +## Can be overriden by environment variable $MIXPATH +## +## $Id: mix.cfg.ex,v 1.4 2003/09/03 16:46:04 packbart Exp $ + +####################### Remailer configuration: ########################### + +## Enable remailer functionality +REMAIL y + +SHORTNAME foo +REMAILERNAME Anonymous Remailer +REMAILERADDR mix@example.net +ANONNAME Anonymous +#ANONADDR nobody@example.net +#COMPLAINTS abuse@example.net + +## Additional capstring flags (e.g.: testing filter mon) +#EXTFLAGS testing + +## Act as an intermediate hop only, forward anonymized messages to +## another remailer +MIDDLEMAN n + +## Supported formats: +MIX y +PGP n +UNENCRYPTED n + +## Only disable these if you really know what they do +#REMIX y +#REPGP y + +## In middleman mode, mail is randhopped through this chain +#FORWARDTO * + +## Filter binaries and replace them with "[...]" +## Note: destroys even PGP messages sometimes +BINFILTER n + +## Allow users to add their address to the dest.blk file by sending the +## remailer a message containing the line "destination-block" +## Note: as no challenge-response mechanisms are used (yet), +## attackers could dest-block arbitrary addresses +AUTOBLOCK y + +## Automatically respond to non-remailer mail and mail to COMPLAINTS address +AUTOREPLY n + +## List statistics on intermediate vs. final delivery in remailer-stats. +STATSDETAILS y + +## List known remailers and their keys in remailer-conf reply +LISTSUPPORTED y + +## Maximum chain length for message forwarding requested by +## Rand-Hop and Remix-To directives +MAXRANDHOPS 5 + +## Maximum size for Inflate: padding in kB. 0 means padding is not allowed +INFLATEMAX 50 + +## Limits the number of allowed recipients in outgoing mail +## Anything that exceeds this number is dropped silently +MAXRECIPIENTS 5 + +## Passphrase to protect secret keys +#PASSPHRASE raboof + +## Maximum message size in kB (0 for no limit): +SIZELIMIT 0 + +## Remailing strategy: +MAILINTIME 5m +SENDPOOLTIME 15m +POOLSIZE 45 +RATE 65 + +## Dummy generation probabilities +INDUMMYP 10 +OUTDUMMYP 90 + +## How long to store packet IDs and incomplete message parts +IDEXP 7d +PACKETEXP 7d + +## Client settings for Rand-Hop: directives and dummy messages +CHAIN *,*,*,* +DISTANCE 2 +MINREL 98 +RELFINAL 99 +MAXLAT 36h +MINLAT 5m + +## This file lists remailers which should not be used in randomly generated +## remailer chains +STAREX starex.txt + +## Path to inews, or address of mail-to-news gateway +## Leave empty to disable mix-post capability flag +## Add more mail2news gateways to increase posting reliability +## (and mail load on your MTA). Additional m2n include: +## mail2news@news.gradwell.net +#NEWS mail2news@dizum.com,mail2news@anon.lcs.mit.edu +ORGANIZATION Anonymous Posting Service + +## Anti-spam message IDs on Usenet (MD5 of message body)? +MID y + +## Precedence: header to set on remailed messages +#PRECEDENCE anon + +## Enable either SENDMAIL/SENDANONMAIL (pipe into sendmail program) +## or SMTPRELAY (SMTP delivery over TCP) +SENDMAIL /usr/lib/sendmail -t +#SENDANONMAIL sendmessage.sh + +#SMTPRELAY smtp.example.net +#SMTPUSERNAME foo +#SMTPPASSWORD bar +#HELONAME example.net +#ENVFROM mix-bounce@example.net + +## Where to log error messages: +ERRLOG error.log +VERBOSE 2 + +## Where to read mail messages from +## trailing "/" indicates maildir-style folder +## leave empty when you feed mixmaster through stdin (e.g. from procmail) +#MAILIN /var/mail/mixmaster + +## POP3 configuration +POP3CONF pop3.cfg +POP3TIME 1h +POP3SIZELIMIT 0 +POP3DEL y + +## Where to store non-remailed messages +## prefix with "|" to pipe into program +## treated as email address if it contains an "@" +MAILBOX mbox +#MAILABUSE mbox.abuse +#MAILBLOCK mbox.block +#MAILUSAGE /dev/null +#MAILANON /dev/null +#MAILERROR /dev/null +#MAILBOUNCE mbox.bounce + +## Where to find variable remailer keyrings and statistics +PGPREMPUBASC pubring.asc +PUBRING pubring.mix +TYPE1LIST rlist.txt +TYPE2REL mlist.txt +TYPE2LIST type2.list + +## If you run your own pinger, make stats/ a symlink to your results directory +## and enable these instead +#PGPREMPUBASC stats/pgp-all.asc +#PUBRING stats/pubring.mix +#TYPE1LIST stats/rlist.txt +#TYPE2REL stats/mlist.txt +#TYPE2LIST stats/type2.list + +## Where to find various textfiles +DISCLAIMFILE disclaim.txt +FROMDSCLFILE fromdscl.txt +MSGFOOTERFILE footer.txt +HELPFILE help.txt +ADMKEY-FILE adminkey.txt +ABUSEFILE abuse.txt +REPLYFILE reply.txt +USAGEFILE usage.txt +BLOCKFILE blocked.txt + +## List of blocked source addresses +SOURCE-BLOCK source.blk + +## List of unwanted header fields +HDRFILTER header.blk + +## List of blocked destination addresses +DESTBLOCK dest.blk rab.blk + +## List of addresses to which Mixmaster will deliver, even in middleman mode +DESTALLOW dest.alw + +## Pid file in daemon mode +PIDFILE mixmaster.pid diff --git a/conf/mix.hlp b/conf/mix.hlp @@ -0,0 +1,45 @@ +This independent remailer uses the Mixmaster remailer software. It is +highly recommended that you obtain a copy of the Mixmaster software to +utilize this remailer. This particular remailer may offer other means of +accessing the remailer service. If this remailer offers other means of +accessing the remailer service, the means will be described later in +this help file. However, only by using the Mixmaster client software +will you assure the highest level of security against third-parties +compromising your privacy. How to obtain the Mixmaster software: + +Mixmaster source code for FreeBSD, Linux, other variants of UNIX, and +Win32: + +If your operating system is a UNIX derivative, simply download and +compile the client from the source code available at +http://prdownloads.sourceforge.net/mixmaster/ + +Mixmaster clients binaries for Win32 (Windows 98, NT, 2000, XP) + +Win32 users may wish to try one of the GUI applications that interface with +Mixmaster: +Omnimix: http://www.danner-net.de/om.htm +Quicksilver: http://www.quicksilvermail.net/ +Jack B. Nymble: http://www.panta-rhei.eu.org/downloads/JBN/ +These are all developed independently of the main Mixmaster distribution. Please +do not contact the Mixmaster development team or the Administrator of the +%RMN with questions about this software. + +For more information about Mixmaster or to contribute to the development +of Mixmaster, please see the following URL's: + +Official Mixmaster Project Site: +http://sourceforge.net/projects/mixmaster/ + +General Information about Remailers and Remailer "how-to" Guides: +http://www.noreply.org/ +http://www.faqs.org/faqs/privacy/anon-server/ +http://www.andrebacard.com/remail.html +http://www.freehaven.net/ +http://www.stack.nl/~galactus/remailers/ + +Remailer Meta-Statistics: +http://stats.mixmin.net + + **** + diff --git a/conf/mlist.txt b/conf/mlist.txt @@ -0,0 +1,48 @@ + +Broken type-I remailer chains: +(austria borked) +(borked senshi) +(cyberiad borked) +(deuxpi senshi) +(dizum borked) +(frell senshi) +(george borked) +(senshi beton) + +Broken type-II remailer chains: +(austria borked) +(borked cyberiad) +(cthulu antani) +(deuxpi tonga) +(metacolo tonga) +(pobox tonga) +(winters tonga) +Last update: Sat 22 Dec 2007 14:50:04 GMT +mixmaster history latency uptime +-------------------------------------------- +cthulu +-- 12:23:02 100.00% +nymkey *-- 12:15:01 100.00% +cyberiad *-- 12:10:30 100.00% +george *-- 11:53:04 100.00% +dizum +-- 11:43:56 100.00% +pboxmix *-- 11:27:59 100.00% +banana +-- 11:16:59 100.00% +borked *-- 11:13:06 100.00% +metacolo *-- 11:01:08 100.00% +hermetix *-- 10:35:00 100.00% +deuxpi *-- 10:25:01 100.00% +cside +-- 11:04:57 99.88% +antani +-- 13:38:02 99.49% +frell --- 16:59:02 99.03% +citrus +-- 14:20:01 98.42% +starwars +-- 13:51:02 98.27% +kroken +-- 10:25:33 96.30% +pobox +-- 11:48:00 95.82% +eurovibes +-- 11:33:00 92.45% +winters +-- 9:52:06 89.99% +beton ___ +-- 64:40:28 64.21% +austria _ +-- 11:04:58 45.96% +tonga +-- 4:48:00 30.70% +bunker +-- 14:50:01 24.07% +hastio 99:59:59 0.00% +panta 99:59:59 0.00% diff --git a/conf/news.hlp b/conf/news.hlp @@ -0,0 +1,59 @@ +You can use this remailer to post messages to Usenet newsgroups. To send +a message to Usenet, insert the "Anon-post-to:" header as per the +examples below. + +================================================================== +To: %RMA + +:: +Anon-Post-To: alt.test,misc.test + +## +Subject: An Anonymous Usenet Post + +This message is anonymous. +=================================================================== +When posting test messages, please use the appropriate test newsgroups such +as alt.test and misc.test. + +The newsgroup alt.privacy.anon-server is not a test newsgroup. Please do +not use alt.privacy.anon-server for testing purposes. + +To post a follow-up to a Usenet article, you must insert a "References:" +header. + +Here is an example as to how to reply to a message that originally +contained the following headers: + +================================================================== +Newsgroups: soc.rights.human +Subject: Re: Are you a witness of torture in West Africa? +Message-ID: <6643215551.110344173@news.newssender_domain.com> +References: <19990101182004.17714.qmail@nym.some_nymserver.com> +================================================================== + +Your anonymous follow-up message should begin as follows. Note the +required blank line between the "To:" header and the double colon. + +================================================================== +To %RMA + +:: +Anon-Post-To: soc.rights.human + +## +Subject: RE: Are you a witness of torture in West Africa? +References: 19990101182004.17714.qmail@nym.some_nymserver.com + +Two weeks ago, soldiers came to our village. The soldiers all had +machine guns. Nobody in our village has any guns, since the police had +come by our village about a year ago and took away all of our guns to +protect us from bandits. There was nothing we could do to resist the +soldiers. The soldiers rounded up all the men, except young children and +the very old. Then the soldiers lead the men away from the village. +About half an hour later, we heard many shots in the distance. When we +went looking for our people, all men were dead. The soldiers had left. +The next day, they went to another village in the [. . .] +================================================================== + ***** + diff --git a/conf/pgp.hlp b/conf/pgp.hlp @@ -0,0 +1,143 @@ +You can use PGP to encrypt messages sent to this remailer if you for +some reason are unable to use the Mixmaster client software. However, +while PGP will securely encrypt the content of a message that you are +sending to the remailer, submitting messages to the remailer that are +merely PGP encrypted without the use of the Mixmaster client software +greatly increases the risk of third parties being able to determine the +identity of the sender (you). + +This remailer primarily supports the ability to submit messages for +remailing without requiring the Mixmaster client software for backwards +compatibility with older remailer client software. + +If you are able to use the Mixmaster software with your operating system +(chances are you can), it is highly recommended that you use the +Mixmaster client software instead. See the earlier section in this help +file on how to obtain a copy of the Mixmaster client software. + +If you cannot use the Mixmaster software, want to use an anonymous +remailer, and are willing to accept reduced security, you can do the +following: + +Send email with Subject: remailer-key to <%RMA> to obtain +a copy of the remailer's PGP key. + +Then do the following: + +1) create a file containing your message +2) insert a BLANK LINE as the first line of the file +3) Insert a "::" as the second line of the file +4) Insert "Anon-To: final_recipient@destination_domain.com" as the + third line of the file. + +At this time, the file should look as follows: + +================================================================== + +:: +Anon-To: final_recipient@destination_domain.com + +This is some anonymized email. +================================================================== + +5) Now encrypt the file with the PGP key of this remailer. + +Finally, email the encrypted file to <%RMA> as +shown in the example below. + +The line "Encrypted: PGP" instructs the remailer to decrypt the message +and process its contents. + +================================================================== +From: remailer_user@sender_domain.com +To: %RMA +Subject: anonymous message + +:: +Encrypted: PGP + +-----BEGIN PGP MESSAGE----- +Version: 2.6.3i + +owE1jMsNwjAUBH3gZMk9PClnUoBPUANpwElW2OBPZD8H0gd1UCP2gduuNDNfIcSH +T4zCbQmtlbzGFM9T0jSD7QVvEzaPcUlBSSWHQclbnR9YWJNp5BFSLdR9CijF3NGx +ybry/1Rsqn4la3a0JiIhLvnYGCu9HFtiC8oIxnlkeuIYe+EH =HgDq +-----END PGP MESSAGE----- +================================================================== + +Even though PGP encryption in itself is very secure, not using the +Mixmaster client exposes some information to parties desiring to +compromise your privacy. This information leakage permits what is known +as "traffic analysis". For example, if someone receives anonymous +messages soon after you sent encrypted messages to a remailer it is +likely that you are the sender of those messages. + +To partially compensate for this information leak, you can instruct the +remailer to delay your messages for some time or send the remailer empty +messages to make such analysis harder: + +If you use the line "Null:" instead of "Anon-To:", the remailer will +simply discard your message. + +You can add a "Latent-Time:" header to the remailer to retain your +message for some time before forwarding it. "Latent-Time: +2:00" would +delay the message for two hours. You can use a random delay by adding +"r", for example "Latent-Time: +5:00r" would delay the message for up to +five hours. For example: + +================================================================== + +:: +Anon-To: final_recipient@destination_domain.com +Latent-Time: +2:00 + +This is some anonymized email. +================================================================== + + +You can chain remailers by using another remailer to send the message to +<%RMA> anonymously. For example, take the message + +================================================================== + +:: +Anon-To: %RMA + +:: +Encrypted: PGP + +-----BEGIN PGP MESSAGE----- +Version: 2.6.3i + +owE1jMsNwjAUBH3gZMk9PClnUoBPUANpwElW2OBPZD8H0gd1UCP2gduuNDNfIcSH +T4zCbQmtlbzGFM9T0jSD7QVvEzaPcUlBSSWHQclbnR9YWJNp5BFSLdR9CijF3NGx +ybry/1Rsqn4la3a0JiIhLvnYGCu9HFtiC8oIxnlkeuIYe+EH =HgDq +-----END PGP MESSAGE----- +================================================================== + +Next, encrypt the message with the PGP key of the %RMN +and send the twice-encrypted message to <%RMA>. + +Similar to a nested Russian matryoshka doll, containing increasingly +smaller dolls inside the each outer doll, you can layer multiple +encryption layers and remailer hops around your message. If this sounds +confusing, just use the Mixmaster client software instead. + +If you send your messages through a chain of several independent +remailers, it will be become increasingly difficult, though not +necessarily impossible, to trace the anonymous message back to you. A +vastly more secure solution is to use the Mixmaster client software to +send your anonymous mail. + +Some remailers supporting PGP encrypted messages offer pseudonymous +"nym" service that allow you to not only send emails privately, but also +receive emails without enabling the sender to determine your recipient +destination email address. For more information about such nym services, +see the following URLs. + +http://lexx.shinn.net/nym/ + +http://riot.eu.org/anon/doc/nym.html + + ***** + diff --git a/conf/pgponly.hlp b/conf/pgponly.hlp @@ -0,0 +1,144 @@ +You can use PGP to encrypt messages sent to this remailer if you for +some reason are unable to use the Mixmaster client software. However, +while PGP will securely encrypt the content of a message that you are +sending to the remailer, submitting messages to the remailer that are +merely PGP encrypted without the use of the Mixmaster client software +greatly increases the risk of third parties being able to determine the +identity of the sender (you). + +This remailer primarily supports the ability to submit messages for +remailing without requiring the Mixmaster client software for backwards +compatibility with older remailer client software. + +If you are able to use the Mixmaster software with your operating system +(chances are you can), it is highly recommended that you use the +Mixmaster client software instead. See the earlier section in this help +file on how to obtain a copy of the Mixmaster client software. + +If you cannot use the Mixmaster software, want to use an anonymous +remailer, and are willing to accept reduced security, you can do the +following: + +Send email with Subject: remailer-key to <%RMA> to obtain +a copy of the remailer's PGP key. + +Then do the following: + +1) create a file containing your message +2) insert a BLANK LINE as the first line of the file +3) Insert a "::" as the second line of the file +4) Insert "Anon-To: final_recipient@destination_domain.com" as the + third line of the file. + +At this time, the file should look as follows: + +================================================================== + +:: +Anon-To: final_recipient@destination_domain.com + +This is some anonymized email. +================================================================== + +5) Now encrypt the file with the PGP key of this remailer. + +Finally, email the encrypted file to <%RMA> as +shown in the example below. + +The line "Encrypted: PGP" instructs the remailer to decrypt the message +and process its contents. + +================================================================== +From: remailer_user@sender_domain.com +To: %RMA +Subject: anonymous message + +:: +Encrypted: PGP + +-----BEGIN PGP MESSAGE----- +Version: 2.6.3i + +owE1jMsNwjAUBH3gZMk9PClnUoBPUANpwElW2OBPZD8H0gd1UCP2gduuNDNfIcSH +T4zCbQmtlbzGFM9T0jSD7QVvEzaPcUlBSSWHQclbnR9YWJNp5BFSLdR9CijF3NGx +ybry/1Rsqn4la3a0JiIhLvnYGCu9HFtiC8oIxnlkeuIYe+EH =HgDq +-----END PGP MESSAGE----- +================================================================== + +Even though PGP encryption in itself is very secure, not using the +Mixmaster client exposes some information to parties desiring to +compromise your privacy. This information leakage permits what is known +as "traffic analysis". For example, if someone receives anonymous +messages soon after you sent encrypted messages to a remailer it is +likely that you are the sender of those messages. + +To partially compensate for this information leak, you can instruct the +remailer to delay your messages for some time or send the remailer empty +messages to make such analysis harder: + +If you use the line "Null:" instead of "Anon-To:", the remailer will +simply discard your message. + +You can add a "Latent-Time:" header to the remailer to retain your +message for some time before forwarding it. "Latent-Time: +2:00" would +delay the message for two hours. You can use a random delay by adding +"r", for example "Latent-Time: +5:00r" would delay the message for up to +five hours. For example: + +================================================================== + +:: +Anon-To: final_recipient@destination_domain.com +Latent-Time: +2:00 + +This is some anonymized email. +================================================================== + + +You can chain remailers by using another remailer to send the message to +<%RMA> anonymously. For example, take the message + +================================================================== + +:: +Anon-To: %RMA + +:: +Encrypted: PGP + +-----BEGIN PGP MESSAGE----- +Version: 2.6.3i + +owE1jMsNwjAUBH3gZMk9PClnUoBPUANpwElW2OBPZD8H0gd1UCP2gduuNDNfIcSH +T4zCbQmtlbzGFM9T0jSD7QVvEzaPcUlBSSWHQclbnR9YWJNp5BFSLdR9CijF3NGx +ybry/1Rsqn4la3a0JiIhLvnYGCu9HFtiC8oIxnlkeuIYe+EH =HgDq +-----END PGP MESSAGE----- +================================================================== + +Next, encrypt the message with the PGP key of the %RMN +and send the twice-encrypted message to <%RMA>. + +Similar to a nested Russian matryoshka doll, containing increasingly +smaller dolls inside the each outer doll, you can layer multiple +encryption layers and remailer hops around your message. If this sounds +confusing, just use the Mixmaster client software instead. + +If you send your messages through a chain of several independent +remailers, it will be become increasingly difficult, though not +necessarily impossible, to trace the anonymous message back to you. A +vastly more secure solution is to use the Mixmaster client software to +send your anonymous mail. + +Some remailers supporting PGP encrypted messages offer pseudonymous +"nym" service that allow you to not only send emails privately, but also +receive emails without enabling the sender to determine your recipient +destination email address. For more information about such nym services, +see the following URLs. + +http://lexx.shinn.net/nym/ + +http://riot.eu.org/anon/doc/nym.html + + ***** + + diff --git a/conf/pubring.asc b/conf/pubring.asc @@ -0,0 +1,544 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.7 (GNU/Linux) + +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 ++bU9O/QNtJkAjQM/aBqoAAABBADRmzLyRGqKmd6qtv1U5LwLtSJzmtTnoBOk9Azp +mLff6YgO4GNcbkzm4O++el0Kzz9d/+S+iYteCMtVkAXfkck97RbrxYVxIhAcXVuJ +Bnfn2wj5Orn9rCIPe57KaYnxJQDZrbANrOgrKVLLKoLbAmBAmh5/PbZjoFfS7ybg +UvWtwQAFEbQrR2VvcmdlIE9yd2VsbCdzIHJlbWFpbGVyIDxtaXhAbWl4bWFzdGVy +Lml0PokAlQMFED9oGqjS7ybgUvWtwQEBPUkEALPOXrPzDiBWuqOTe2qvNAJfREvd +2nIIavdRMESbD1UcYnf/7AfmqpsZpIIXW279PRq3r29IuNyLo/TAT0Cw2va9rP8I +6xfLsEsduH9Qjt0kC9NCOI/CCaXHgk1E09YL1iFbVSrDSq6vfVIknO+sTCjucUce +qwHXDRJZqiZ7QoGxmQCNA0UE/x4AAAEEAKe6Oc1dgcLcWgZW2CbxmoQWFoKeOAJO +wrjb5cYUv8+Q92h2og3uosjF8KvU/ilQ8tC2BHWavAh98+TxFVIhbgf7z160Z62R +ELZ0TUm3fuWv6lpNGGLLHuWtGRErN6P5j1n1eu1B9h4B9vQMWmIt8n9LccvMjkok +6HgrDDB9/sG5AAURtEFDeWJlcmlhZGUuaXQgQW5vbnltb3VzIFJlbWFpbGVyIDxt +aXhtYXN0ZXJAcmVtYWlsZXIuY3liZXJpYWRlLml0PokAlQMFEEUE/x54Kwwwff7B +uQEB7IMD+wb3UdB6vxsu4l8R62lPkPudu/pDfL8t+QZ3rd24UdjHvf2mF0/51cev +bfsP9c/AhfrnpvUYjpxZ5mrgCkkeNzknUnk1MF/L1UyHAkqKKnF2rw+voaOtkFjD +d1midf9aEWQ0wX/SDgDXkhxZ5wdAK8Jv7xhImHxn63adNsgUEE8+iQEcBBABAgAG +BQJFBQAiAAoJEHCkr+X+kMzIcDYIAJwJj/B7rB4RToF+yyYpTqkNQIHhyjji2G1a +3O1IbYV3Hhvhs8Cq0GzXNQ+My+tiNXKURa/ZeJekHwbEOPPT7uNAgsT9bW6CQF97 +OhHoMBr6xkDRfU+Ne/FSQw9yqVaIRtT4SVDGQVTaF3s2PiTPyetrHsEDGFtA6Kay +YiJC+WXgZ1BEFGnVil1Qkc9DVYHNr/6RqCYSrm0xN1iOnOqb4ZPiSII7AZuOMO0B +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 +xohUuLs521kTqoY= +=NUVh +-----END PGP PUBLIC KEY BLOCK----- diff --git a/conf/pubring.mix b/conf/pubring.mix @@ -0,0 +1,384 @@ +antani mixmaster@firenze.linux.it d178ebcb1b259970d8d224c1f53f69b7 2:3.0rc1 MCNm 2007-06-25 2008-07-19 + +-----Begin Mix Key----- +d178ebcb1b259970d8d224c1f53f69b7 +258 +AAS3PnAAJxD4O8nW3xeTN29HQX9Yg3APRkrpukwC +3YxjiDhglUKnLkX+QxdS46IHf05d9ISJsF2c/M3i +1ftd4UdoJcRN4OgnQ9W0Qo/ZfnFDYEUNeXkra7XK +XftHkp+C2zAN7STWWuw/1YHsY6D5Hb0zOXTJvlA8 +DBCxKxJmtlhAEwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +austria mixmaster@remailer.privacy.at 1a48dd7e5f9740dfc174dacdcbc673e6 2:3.0b2 C 2007-03-18 2008-04-11 + +-----Begin Mix Key----- +1a48dd7e5f9740dfc174dacdcbc673e6 +258 +AASxWLMGH4acTiKixL4effVMcfsP3d39INxJhrpH +xqStsBGAzFAdvURRyt3q3reYIMH/K4YBFwFM0nMm +I6egh9N+IaYmqck0A+GFxwBDDFdqFz2GNhdBqr+h +ahEv/BbNP3LBSIA31m4ElaYFfc7ebZqmAKIxUioh +pc+G6t6L9hgtlQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +banana banana@mixmaster.mixmin.net 67e7628c4e8c10f4bce3da58bf2f8bb5 2:3.0rc1 CNm 2007-06-16 2008-07-10 + +-----Begin Mix Key----- +67e7628c4e8c10f4bce3da58bf2f8bb5 +258 +AATDpYXFPE+/Zol2PDUS+Y4J2s6SbNSDpNpMT8GS +QeogwFBGS6FijkL1xWX8zGh5DE+VOLT+TgW6yBNV +ZB+VTLLmL1rrqeE/ZIP2mcL32bU3yVmaHCN38JYI +3CmBqhUMN2gTlhZF2MMP3mr79HmnCr8OwU2YrTjV +4WV96sbnRXc3OwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +beton remailer@hyperreal.info bbcca4038804c8ebbb2b92038a412d8b 2:3.0rc1 MC 2007-11-11 2008-12-05 + +-----Begin Mix Key----- +bbcca4038804c8ebbb2b92038a412d8b +258 +AASuV2OX69CDrwpS/gJ+Jz871GnoyH6KK90dXz4i +DzDTZ1FZd5oNf3kT07DAaLRVUzodkMKHFbfMvqT/ +/jjdVojbtntmNHOwkzKj9UMxu9v8XLB8+Lfw8Kqi +d3nLZyeTIRoVEP0Kl8bY+9hxKR91QBYhcdvAvn3j +XWhrzjnTB3fyIwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +borked remailer@pseudo.borked.net 46e927c921aacce16986d5e0ec31ac4b 2:3.0b1 CNm 2007-04-20 2008-05-14 + +-----Begin Mix Key----- +46e927c921aacce16986d5e0ec31ac4b +258 +AASnFzxxJrV2CDkw0z1q3MNKx90nkI51y4ZEad4n +y42OkJmuW8y4uVfVNDc7SUMW6eQRISR0oRgWY0IQ +PyuGLLTZZg1BW429aUa0VqK5uwYWCcZEuiUkQLUK +AjMM+8rE834vuxWg1/K9zr3H3NJ2vMm8tHoHIqMK +/vf1Nq770RqjawAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +bunker mixmaster@mixmaster.thebunker.net 0bd3320d57af38db5ea3432df2bf1f9e 2.9b38 CNm + +-----Begin Mix Key----- +0bd3320d57af38db5ea3432df2bf1f9e +258 +AASx+0mGBuPSJicU6ZauDWU0GClmHYbPY9EfF8pU +8P229q2NgUTok2052HLAIEKMpnS85gS1eHvTmOIi +1J368PRroRGD5HzX0fhXbkpzmp4we0IJeRIdMCNC +DIwnzu2wlXM+LSxYnXOKzIP8W9CL2PDYdyzJ/+/P +2X8l641JJniJoQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +citrus mix@outel.org 310b8456beb23663965c6483fc45aab7 2:3.0b1 MC + +-----Begin Mix Key----- +310b8456beb23663965c6483fc45aab7 +258 +AASyTIuWDEit5JGL5mvdfU2tqaBQNU7Lr35PA0zE +yBr6T5Hz35/8ojQ4h00/hDdDS6D7196qb7k7p0Gs +HV4wGjjgOX4mTRKB7KU54DE++OUqXL7vSRrVlAXr +7vNDDRoPXfwRurR+umvwjrVaqNEIwgGi/aKOO3cH +chDXYzKwXJt/9QAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +cside cside@cside.dyndns.org 0a7c90daed1c97235e3b3f80b7a0c32f 2:3.0rc1 MC 2007-02-12 2008-03-08 + +-----Begin Mix Key----- +0a7c90daed1c97235e3b3f80b7a0c32f +258 +AATB3o78sdBFzcpZqYKizgveaSqUynPS3OObdWgX +27dzplSAV8smR/A55kAukgqKptlSAB6FxxbexapI +YXLz7p9cpH+vTWa6HdiWjORxD/bVEK7VghajRH3f +WXPhjD5npcYy6UhOFi3b045Sc1ddhtdBzJfUmZPB +q4aQIHqufTL/kQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +cthulu mixmaster@cthulu.joatcrafts.org 03395f366dc6a70e673ac5d548ca8ec1 2.9beta32 MC + +-----Begin Mix Key----- +03395f366dc6a70e673ac5d548ca8ec1 +258 +AAS2XJa9bQHEjEb6FfSOaPnfk95nxQEVeAF5gpGA +b8Y9vr8z5qaoNasBmNctbVxL0MN4VmVxtpFje1pl +eB7BV7O76rH2c1InKLT3brSYUNGLWmFTqbwC3CQl +GaqUmmfJTG2g4OC3LvA+CS+1h5w5Lz7zQEsP6h7C +CrBg6fpWBXmYLQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +cyberiad mixmaster@remailer.cyberiade.it dbf45caec67b765aac8d64f6ce5dd2d8 2:3.0b2 CNm 2007-11-07 2008-12-01 + +-----Begin Mix Key----- +dbf45caec67b765aac8d64f6ce5dd2d8 +258 +AATfA1FNEh9K/bPsz+6xguyZXIQo1zzLw2/BXBvI +BehyJT5ay5AROUVFxsAxZJFiUXrOniSIzBt7l3Ac +vE2B4KTAf54ScJk87rSErY8iP4sQeMMZRSdU3Cof +9qVbdDQFoHPNJXotNCY8iuGA5wrxK/faMhq5KQcd +1uJzS0Pj02spkQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +deuxpi anon@deuxpi.ca 43d6f1186c5193548c8b2b38fcc051a5 2:3.0b2 MCNm 2007-06-12 2008-07-06 + +-----Begin Mix Key----- +43d6f1186c5193548c8b2b38fcc051a5 +258 +AAS7sg8J+q0svmNi6lbf8ywZZEWGG1cScSDQqDsy +NjgMAzj7nzfjdrNBXdxH6K+uJVT37xJ6TGELDMnA +WeBb6K1ICT5leFMzOnmO+ruzOCOTkFVXMXntbqz0 +CLO+Wr6yw+BF6jYr2nNK1+phiF7zqa+2yDrihife +pYOJcTKFDJEZVwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +dizum remailer@dizum.com 314d6e1d1482e73781925562ef41cb56 2:3.0rc1 CNm + +-----Begin Mix Key----- +314d6e1d1482e73781925562ef41cb56 +258 +AAS9utvoS0r+9TmLgXnh4Al6b4BYTL71JVIg6SJ/ +RhE7KAJTxrQDV6JmTfTtE2IwvPiO6KbbzHk4LMwP +EkFfFi9sIE+N8Ced1QjfgWt5Kr7lrVARzIzUi9B4 +q5Q7XxJ1ttS2d+di2CvuDbREjZfhN8d9cdrwElD6 +tCWVa8GtwkrA7wAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +eurovibes mixmaster@eurovibes.org 9abe18b1fe9706f477214b6c25d815ce 2:3.0b2 MCNm 2007-09-01 2008-09-25 + +-----Begin Mix Key----- +9abe18b1fe9706f477214b6c25d815ce +258 +AASe1c2QOEZ1bGuHsez8/7Mh0uwT7nlVHua0byW9 +2VfPQQOBH2WizhqEoBL17SaCXtDRWqmcWjscKAiu +9JKcMeV9doqJufyBSL72lMllZptHNa7NVeTz1ORd +RpKOFHiPPHosR6swoNnQx3rMQQ1UukqlOnWjrYuQ +rluhHsFfp+wsjwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +frell godot@remailer.frell.eu.org 36a413ef0c5f70a40fa981a15a838d6d 2:3.0rc1 CNm 2007-09-12 2008-10-06 + +-----Begin Mix Key----- +36a413ef0c5f70a40fa981a15a838d6d +258 +AAS8atl2d209zkTZ0NYUOK3IUf547Wp3fy4X5xKC +NmHFrvwzN5MR6FWDmc+GxyYe2yfbguumMPpMxaPy +KKfsyxkdbkQltMPT7Klg2YXOIdcHjFOB+rDhgwaA +CE/6v+3oNSJLV4vynTO70VjlIeACTQB74dzDzlA5 +P6PNWBpjFmRfwQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +george mix@mixmaster.it ab3475256b54ca81e22654f3140059d1 2:3.0rc1 CNm + +-----Begin Mix Key----- +ab3475256b54ca81e22654f3140059d1 +258 +AATvwvPxB6WRF/M271TbI6kYo5o3Lex7slhid2me +ZhIYqD6/3oocuKAKjlcAuuNeHEYdODzBTOtT6q/e +6qJci0JTawm1N6wlQf7Ec4Cf9iHk/bDG9z8n3pUg +/pYPmXyTJhsUaev9G0pDmlm7hgfP8e/FU3b3rrAs +Cs7ICwKXsZHCMQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +hermetix mix@hermetix.org 4abed36ded98d55cf314b4371d32e63b 2:3.0rc1 CNm 2007-08-06 2008-08-30 + +-----Begin Mix Key----- +4abed36ded98d55cf314b4371d32e63b +258 +AASvG7+cR8y22Q74hdeBa7H7xmEiN7hmhFTfkdvM +2szIAfEF4bt81vitMVfjlaeFOBCKdos6H01ku6Vl +YyFDAqc8UqUIaIpE12Gj0bzt7RaqiFHyBNSGPTzo +lD5t9TsIheqgZXBYfJYtdB20JCgg58trGR20EhKp +YEKl03Luw4hGDwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +kroken remailer@kroken.dynalias.com dce5b28b21c0c4549dd2f60bd8e132bb 2:2.9.1 MC + +-----Begin Mix Key----- +dce5b28b21c0c4549dd2f60bd8e132bb +258 +AATIsmPImwHWKUoZYEcmSG3mnVR1N8HBPTmgURMT +D7TEkm5Ft50lgUEa6so+mEybcKhDucS6a8ggWs0Z +dC+xd3V7fE/vkUrTz2y/agZUhxtg8Lli/JzU6/0T +DuXKCl/RPkk9TQjza2f/kONZ5g7SOEs001GpYWx6 +m8nHp2St6CFjnQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +metacolo mix@remailer.metacolo.com 134c535b461b5777fb77acf26c4fc344 2:2.9.1 CNm + +-----Begin Mix Key----- +134c535b461b5777fb77acf26c4fc344 +258 +AASxBgMo4LysBt8XcB3twGhd1VLbgMaIcjnxopYJ +Kf2yzon5oma+RcYLcZb4xkDPUOZurnt5QBQ9YlUt +EtfC8nKFlGY1bwAAFsa1+sne94U0kiwEqC85Y//3 +BS0xJgUUYf45DqChbP67Y6WbVCbiWo9XBdB9s573 +gC7o1+pcOCuX7wAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +nymkey mixmaster@nymkey.com e8c9e711fa87da8f2537ba4975015a21 2:3.0b2 CNm 2007-11-25 2008-12-19 + +-----Begin Mix Key----- +e8c9e711fa87da8f2537ba4975015a21 +258 +AASsmXxFWovlEqSDF1lTLZOoFXBFDZegheR9iWGR +0d36yq1I/JpVKtVp1ZZr4Bs0ivjgtFiS8gDJOF7i +InukP7wBfNfPl2LPBAxpwmDbvt2wI2y44+0XloQQ +Y+hqiZnhkW0UA97IQ2UauIfKieQdJ2D1GBVR9+r5 +dzQAgLqlBVIbuQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +pboxmix mixmaster@pboxmix.winstonsmith.info 065247b5b9a598c3864169963ef7943e 2:3.0b2 CNm 2006-12-31 2008-01-25 + +-----Begin Mix Key----- +065247b5b9a598c3864169963ef7943e +258 +AATG36o9krh9bM4l8StENw9JTzIYJnA5xYvxbYJT +8MLIThhYtwn3KUhKM/J7ywsN3GOoqeuPu6bsSchc +3VOhEfh5mDX9Sk/LVplSRd0Rx2hr5Z1ws89Crk7d +ZHzgIZc4PXEShftuToWN9yEiznyFeW3Pr0TmcjPb +sistHq5vwSUVIQAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +pobox mix@antagonism.org 03447beb791e53062dbf6ce6b074bbb1 2:3.0rc1 MC 2007-11-21 2008-12-15 + +-----Begin Mix Key----- +03447beb791e53062dbf6ce6b074bbb1 +258 +AASlYQieOuO/RjwF0kpFDtxm9ptnidj6d5eDKC9/ +TJ4hYPa4I6koM/wRzTwDKyrEs8Q9SsbBouksvm4m +n/l24DWjWrBK4xpkg0aMduyXvw4NYK+tXmBt0acr +eSb9y4sBNoBF9I5b0mjMyAHPDhExp8bh9ytqZV9K +nFqtS0nDmkjenwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +starwars mixmaster@tatooine.homelinux.net 912819a4f778f7ffd37dd6d1d96c3814 2:3.0rc1 MCNm + +-----Begin Mix Key----- +912819a4f778f7ffd37dd6d1d96c3814 +258 +AAS5rSbE3GryA6Ue5cokxi8yXY6STITER+Zfr8xq +LvKy+JD5fV4AYYMaN3dar9vjcA72JiBocWGDUcs2 +qXUhmugghqsrPQOcWyY8Id9i1ww+00fEgaqD8pTe +TcX3pOBVbrp2nm6r0QsM+BekUY0CxlAedalFp3x6 +j8m8hNRDOmyDLwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +tonga remailer@cypherpunks.to 70d5742c277080317d4161f8c41b6592 2:3.0a3 MCNm 2002-09-12 + +-----Begin Mix Key----- +70d5742c277080317d4161f8c41b6592 +258 +AASXcXjmf6JdlT28ivHvkgr+JYdtTBL2sBXa6YSv +sJ7usVBpgbdknuWcw7FC5kCqdyaaUd7s/y6dNqAu +/QuudS29RlochxJ5QqwUcFv/xNnej/flzVeEdfdU +McgYOUG4cBZ/D0X8lUqc85a31qeNvmIEU3RRaKPf +mgMEl6p5YropFwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + +winters mix@remailer.antagonism.org b5fa82ee0fb8c2a41b5a90c0983d8344 2:3.0rc1 MC 2007-07-05 2008-07-29 + +-----Begin Mix Key----- +b5fa82ee0fb8c2a41b5a90c0983d8344 +258 +AATMBYHz/jt2yIGLfxNkA0g/ca1feheiOnuwE4uA +nZNL5mu5qbinV1aC0x1HwyRzuL+7rdCu5y9P+CvW +qRPxtoflkbfqthS/Su5smsn8kZHtdjwsIYUTjs5j +QBSDqsxKpfHHP0aQgBqvDtRRo4RH/00jG40YFyWD +tZPRXEDkxR7b5QAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAB +-----End Mix Key----- + diff --git a/conf/rab.blk b/conf/rab.blk diff --git a/conf/reply.txt.in b/conf/reply.txt.in @@ -0,0 +1,32 @@ +This message is being sent to you automatically in response to an email +that you sent to <%RAA>. + +Most likely, you tried to reply to an email that has been sent through +this service. If you did not send an email to <%RAA>, +please ignore this message. + +The %RMN is a free service that +allows individuals including crime victims, domestic violence victims, +persons in recovery, and others, such as those living under oppressive +regimes, to communicate confidentially in a manner that ensures their +privacy under even the most adverse conditions. + +To block individuals using this remailer from sending email to your +address in the future, please send a message to <%RMA> +containing the line + +DESTINATION-BLOCK + +anywhere in the body text of the email. You can simply forward this +entire email to <%RMA> using your email +program for your current email address to be permanently blocked +from users of the %RMN. + +For more information about the %RMN Administrator's +strict anti-abuse policy, please send a blank email to +<%CA> + +Sincerely, + +-- The %RMN Administrator + diff --git a/conf/rlist.txt b/conf/rlist.txt @@ -0,0 +1,61 @@ +$remailer{"antani"} = "<mixmaster@firenze.linux.it> cpunk max mix middle pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; +$remailer{"austria"} = "<mixmaster@remailer.privacy.at> cpunk max mix pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord klen1024"; +$remailer{"beton"} = "<remailer@hyperreal.info> cpunk max mix middle pgp repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord klen10000"; +$remailer{"borked"} = "<remailer@pseudo.borked.net> cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop3 reord post klen1024"; +$remailer{"citrus"} = "<mix@outel.org> cpunk max mix middle pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord"; +$remailer{"cyberiad"} = "<mixmaster@remailer.cyberiade.it> cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post"; +$remailer{"deuxpi"} = "<anon@deuxpi.ca> cpunk max mix middle pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; +$remailer{"dizum"} = "<remailer@dizum.com> cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post klen64"; +$remailer{"frell"} = "<godot@remailer.frell.eu.org> cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post klen1024"; +$remailer{"george"} = "<mix@mixmaster.it> cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post"; +$remailer{"hastio"} = "<anon@remailer.hastio.org> cpunk mix hybrid pgp latent ek ekx esub cut hash repgp remix ext max test inflt75 rhop6 klen1000"; +$remailer{"hermetix"} = "<mix@hermetix.org> cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post klen5000"; +$remailer{"kroken"} = "<remailer@kroken.dynalias.com> cpunk mix middle pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop20 reord klen1024"; +$remailer{"metacolo"} = "<mix@remailer.metacolo.com> cpunk mix pgp repgp remix latent hash cut test ek ekx esub inflt50 rhop20 reord post"; +$remailer{"nymkey"} = "<mixmaster@nymkey.com> cpunk max mix pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; +$remailer{"panta"} = "<remailer@panta-rhei.eu.org> cpunk mix hybrid hcnews pgp latent ek ekx esub cut hash post repgp remix reord ext max test inflt75 rhop5 klen1000"; +$remailer{"pboxmix"} = "<mixmaster@pboxmix.winstonsmith.info> cpunk max mix pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; +$remailer{"senshi"} = "<senshiremailer@gmx.de> cpunk middle pgp latent ek ekx esub cut hash repgp reord ext max test inflt10 rhop2 klen200"; +$remailer{"starwars"} = "<mixmaster@tatooine.homelinux.net> cpunk max mix middle pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post"; + +Broken type-I remailer chains: +(austria borked) +(borked senshi) +(cyberiad borked) +(deuxpi senshi) +(dizum borked) +(frell senshi) +(george borked) +(senshi beton) + +Broken type-II remailer chains: +(austria borked) +(borked cyberiad) +(cthulu antani) +(deuxpi tonga) +(metacolo tonga) +(pobox tonga) +(winters tonga) + +Last update: Sat 22 Dec 2007 14:50:04 GMT +remailer email address history latency uptime +----------------------------------------------------------------------- +nymkey mixmaster@nymkey.com *-- 12:06:55 100.00% +george mix@mixmaster.it *-- 12:01:01 100.00% +kroken remailer@kroken.dynalias.com +-- 11:11:08 100.00% +cyberiad mixmaster@remailer.cyberiade.it *-- 11:08:55 100.00% +hermetix mix@hermetix.org *-- 10:35:57 100.00% +borked remailer@pseudo.borked.net *-- 10:18:00 100.00% +dizum remailer@dizum.com +-- 10:34:31 99.94% +metacolo mix@remailer.metacolo.com *-- 11:56:00 99.86% +antani mixmaster@firenze.linux.it +-- 13:52:33 99.83% +pboxmix mixmaster@pboxmix.winstonsmith.i *-- 11:49:00 99.80% +citrus mix@outel.org +-- 14:16:05 98.71% +starwars mixmaster@tatooine.homelinux.net +-- 11:44:55 97.44% +frell godot@remailer.frell.eu.org +-- 14:32:02 96.77% +senshi senshiremailer@gmx.de ___ +-- 16:50:04 76.28% +beton remailer@hyperreal.info ____ +-- 18:10:57 71.85% +deuxpi anon@deuxpi.ca *-- 11:37:00 52.80% +austria mixmaster@remailer.privacy.at _ +-- 12:14:01 45.38% +hastio anon@remailer.hastio.org 99:59:59 0.00% +panta remailer@panta-rhei.eu.org 99:59:59 0.00% diff --git a/conf/type1.hlp b/conf/type1.hlp @@ -0,0 +1,100 @@ +This remailer will permit you to remail messages without using the +Mixmaster client software or PGP. This mode of operation is known to be +insecure and should generally be used for testing purposes only. The +operator of this remailer, all system administrators of the many +machines through which your email will pass on the way to its +destination, and any 15-year-old-hacker that may have broken into any of +the many machines through which your email will pass may be able to +determine that you are the original sender of the email. + +However, you may find this insecure mode useful for testing and +debugging purposes or to just send a quick email without exposing your +real email address to spam harvesters gathering email addresses from +mailing lists. To use the insecure mode, send mail to <%RMA>. Place a +blank line into the first line, two colons in the second line of your +message, and the line "Anon-To: address" in the third line of your +message. Follow that with another blank line and begin your message. For +example: + +================================================================== +From: remailer_user@sender_domain.com +To: %RMA Subject: anonymous message + +:: +Anon-To: final_recipient@destination_domain.com + +Dear Domestic Violence List Members, +My husband has physically abused me for most of the 18 years of our marriage. +I can't tell you how many times I had to come up with excuses as to why I had +those bruises or that black eye. I stayed in the marriage for the sake of +our daughter. +But recently, my husband has started to touch our 14-year-old daughter. +I don't know what to do. I am afraid my husband will kill me if I say +something. I am even more afraid for my daughter. I have no money; my +husband controls all the bank accounts. What can I do? + +Please help, +-- Desperate. +================================================================== + +The remailer will remove all header lines, and forward the message to +the destination. The following e-mail would be delivered to +<final_recipient@destination_domain.com >: + +================================================================== +From: %RMN <%RAA> +Comments: This message did not originate from the Sender +address above. It was remailed automatically by anonymizing remailer +software. Please report problems or inappropriate use to the remailer +administrator at <%CA>. +To: final_recipient@destination_domain.com + +Dear Domestic Violence List Members, +My husband has physically abused me for most of the 18 years of our +marriage. +I can't tell you how many times I had to come up with excuses as to why +I had those bruises or that black eye. I stayed in the marriage for +the sake of our daughter. +But recently, my husband has started to touch our 14-year-old daughter. +I don't know what to do. I am afraid my husband will kill me if I say +something. I am even more afraid for my daughter. I have no money; my +husband controls all the bank accounts. What can I do? + +Please help, +-- Desperate. +================================================================== + +You frequently will wish to include a Subject or other header lines in +your remailed email. You can insert header lines in the remailed message +by preceding them with a "##" line: + +================================================================== +From: remailer_user@sender_domain.com +To: %RMA + +:: +Anon-To: final_recipient@destination_domain.com + +## +Subject: Re: Remailer Test Message +In-Reply-To: Your message of "Tue, 12 Jan 1999 22:47:04 EST." +<199901130247.WAA02761@destiation_domain.com> + +Dear Desperate, +Just like you, I was stuck in an abusive marriage for +many years. I don't need to tell you what you already know: if not for +your sake, for the sake of your daughter, you need to get away from your +husband immediately. At the moment, you may think your husband has all +the power and that you are powerless. You are not powerless. Contact the +National Center against Domestic Violence today and ask about the +address and phone number of a women's shelter near where you live. The +people there will show you how you can free yourself from the yoke of +brutality and protect your daughter from the worst. + +Please post another anonymous email to this list if you are having any +difficulties in locating a women's shelter. + +-- Broken Free +================================================================== + **** + diff --git a/conf/usage.txt.in b/conf/usage.txt.in @@ -0,0 +1,24 @@ +Subject: Your email to %RMA +Reply-To: <%RMA> + +This message is being sent to you automatically in response to an email +that you sent to <%RMA>. +If you did not send such an email, please ignore this message. + +This remailer is a free service that allows individuals including crime +victims, domestic violence victims, persons in recovery, and others, +such as those living under oppressive regimes, to communicate +confidentially in a manner that ensures their privacy under even the +most adverse conditions. + +To obtain information on how you can use this service, please send an +email with subject "remailer-help" to <%RMA>. + +Should you have received an unwelcome message through this service or to +report problems with this service, please contact the Administrator at +<%CA>. + +Thank you for your interest in secure and private communications, + +-- The %RMN Administrator + diff --git a/idea.txt b/idea.txt @@ -0,0 +1,34 @@ +This Software/Hardware product contains the algorithm IDEA(TM) as +described and claimed in US Patent No. 5,214,703, EPO Patent +No. 0482154 and filed Japanese Patent Application No. 508119/1991 +"Device for the conversion of a digital block and use of same" +(hereinafter referred to as "Algorithm"). Any use of the Algorithm for +Commercial Purposes is thus subject to a license from Ascom Systec +Ltd. of CH-5506 Mägenwil (Switzerland), being the patentee and sole +owner of all rights, including the term IDEA(TM). Commercial Purposes +shall mean any revenue generating purpose including but not limited to + +i) using the Algorithm for company internal purposes (subject to a +Site License). + +ii) incorporating an application software containing the Algorithm +into any hardware and/or software and distributing such hardware +and/or software and/or providing services related thereto to others +(subject to a Product License). + +iii) using a product containing an application software that uses the +Algorithm (subject to an End-User License), except in case where such +End-User has acquired an implied license by purchasing the said +product from an authorized licensee or where the End-User has already +signed up for a Site License. +All such commercial license agreements are available exclusively from +Ascom Systec Ltd. and may be requested via the Internet World Wide Web +at http://www.ascom.ch/systec/infosec.html or by sending an electronic +mail to IDEA@ascom.ch. Any misuse will be prosecuted. + +Use other than for Commercial Purposes is strictly limited to data +transfer between private individuals and not serving Commercial +Purposes. The use by government agencies, non-profit organizations +etc. is considered as use for Commercial Purposes but may be subject +to special conditions. Requests for waivers for non-commercial use +(e.g. by software developers) are welcome. diff --git a/mixmaster.1 b/mixmaster.1 @@ -0,0 +1,1136 @@ +.TH MIXMASTER 1 "Mixmaster Version 3.0" +.\" $Id: mixmaster.1 974 2008-03-03 17:40:11Z rabbi $ +.SH NAME +mixmaster \- anonymous remailer software +.SH SYNOPSIS +.B mixmaster +[\fB\-hpmdSvT\fR] +[\fB\-t \fIuser@host\fR] +[\fB\-g \fInewsgroup\fR] +[\fB\-s \fIsubject\fR] +[\fB\-a \fIfilename\fR] +[\fB\-l \fImix1,mix2,mix3,...\fR] +[\fB\-c \fInum\fR] +[\fIuser@host\fR] +[\fIfilename\fR] +.PP +.B mixmaster +[\fB\-f\fR[\fBrfg\fR] \fIfilename\fR] +.PP +.B mixmaster \fR[\fB\-RGKSP\fR] +.SH DESCRIPTION +Mixmaster is an anonymous remailer. Remailers provide protection +against traffic analysis and allow sending mail anonymously or +pseudonymously. +.PP +In the non-interactive mode, Mixmaster reads a message from its +standard input or from a file. Destination address and input file can +be specified in the command line. If no address is given in the +command line, the input file is expected to contain a message complete +with mail headers. +.SH OPTIONS +.TP +.B "\-h, \-\-help" +Print a summary of command line options. +.TP +.B "\-V, \-\-version" +Print version information. +.TP +.B "\-\-about" +Print authorship and copyright information. +.TP +.B "\-\-config=\fIfilename" +Read configuration from an alternate file. +.TP +.B "\-t, \-\-to=\fIuser@host" +Add the destination address(es) to the message header. The input file +contains the message body without headers. +.TP +.B "\-g, \-\-post-to=\fInewsgroup" +Add the newsgroup(s) to the message header. The input file +contains the message body without headers. +.TP +.B +\-p, \-\-post +Post the message to Usenet. +.TP +.B +\-m, \-\-mail +Send the message as electronic mail. (This is the default.) +.TP +.B "\-s, \-\-subject=\fIsubject" +Add the +.I subject +to the message header. +.TP +.B "\-\-header=\fI'Header: text' +Add the header line to the message header. +.TP +.B "\-a, \-\-attachment=\fIfilename" +Attach +.I file +to the message. +.TP +.B \-\-encrypt +Encrypt the message using the OpenPGP format. +.TP +.B \-\-sign +Sign the message using the OpenPGP format. +.TP +.B "\-l, \-\-chain=\fImix1,mix2,mix3,..." +Use this remailer chain to send the message. Alternatively, the input +message may contain a pseudo-header +.BR Chain: . +If no chain is specified, Mixmaster will use a chain of four random +remailers. +.TP +.B "\-T, \-\-type\-list" +Display the contents of the +.BR type2.list +file. +.TP +.B "\-c, \-\-copies=\fInum" +Send +.I num +copies of the message to increase reliability. +.TP +.B \-d, \-\-dummy +Generate a dummy message as protection against traffic analysis. +.TP +.B \-S, \-\-send +Send the message(s) from the pool. +.TP +.B \-v, \-\-verbose +Output informational messages. +.TP +.B "\-f\fR [\fIfile\fR]" +Read a mail folder or news article. This function requires ncurses support. +.TP +.B "\-fr\fR [\fIfile\fR]" +Reply to a message. +.TP +.B "\-ff\fR [\fIfile\fR]" +Post a follow-up to a message. +.TP +.B "\-fg\fR [\fIfile\fR]" +Send a group reply to a message. +.TP +.B "\-\-update-pinger-list" +Download an updated all pingers list file. +.TP +.B "\-\-update-stats\fI[=source\fR]" +Download updated stats. +.SS Remailer options: +.TP +.B "\-\-config=\fIfilename" +Read configuration from an alternate file. +.TP +.B \-R, \-\-read\-mail +Read a remailer message from standard input and store it in the pool. +.TP +.B \-I, \-\-store\-mail +Read a remailer message from standard input and store it in the pool +without decrypting it immediately. It will be processed the next time +Mixmaster processes the queue (called with \fP-M\fP or in daemon mode). +.TP +.B \-P, \-\-pop-mail +Read mail from the POP3 servers listed in +.BR pop3.cfg . +.TP +.B \-M, \-\-remailer +Check if it is time to perform the regular remailer actions: +Send messages from the pool, get mail from POP3 servers and keep the +internal files up\-to\-date. +.TP +.B \-D, \-\-daemon +Detach from the console and process the pool, get mail and update the +internal files at regular intervals. +.TP +.B \-\-no-detach +Run as daemon but do not detach from the terminal (This option is +only useful together with \fB--daemon\fP). +.TP +.B -G, \-\-generate\-key +Generate a new remailer key. +.TP +.B \-K, \-\-update\-keys +Generate remailer keys if necessary. +.TP +.B \-S, \-\-send +Force sending the message(s) from the pool. +.TP +.B \-\-install\-svc +Install the Mixmaster Service on Win32. +.TP +.B \-\-remove\-svc +Remove the Mixmaster Service on Win32. +.TP +.B \-\-run\-svc +Run the Mixmaster Service on Win32. +.TP +.B \-\-redirect +Read a Mixmaster packet from stdin and route it through a chain given with +.B \-\-no\-ask\-passphrase +Do not ask for the remailer passphrase even if we don't have it compiled in, +don't have it in the config file, don't have it in the environment and we are +on a tty. +\fB\-\-chain\fP. +Note that this may corrupt the packet if there is not enough space in the +headers (that is, if there are more than 20 hops total). This function is +not normally needed but may come in handy in certain cases. +.SH CONFIGURATION +Mixmaster reads its configuration from the file +.B mix.cfg +in its working directory. The configuration file consists of lines of +the type +.PP +.I VARIABLE values +.PP +and of comments, which begin with a +.B # +character. The variables have reasonable default values, but it is +useful to create a configuration file using the +.B Install +script when setting up a remailer. +.PP +All configuration variables can be overridden from the command line, +e.g. +.B mixmaster -S --POOLSIZE=0 --RATE=100 +will send all messages currently in the message pool. +.SS Client configuration: +.TP +.B ADDRESS +Your address for sending non-anonymous messages. +.TP +.B NAME +Your real name (used for sending non-anonymous messages). +.TP +.B MAILtoNEWS +Address of a mail-to-news gateway. Default: +.BR mail2news@nym.alias.net . +.TP +.B CHAIN +Default chain for anonymous messages to be sent. +.B CHAIN +is a comma-separated list of remailer names or addresses. +A +.B * +represents a random reliable remailer. Default: +.BR *,*,*,* . +.TP +.B NUMCOPIES +Number of redundant copies of an anonymous message to be +sent, unless specified otherwise on the command line. +Default: +.BR 1 . +.TP +.B DISTANCE +When selecting random remailers, the chain will contain +.I DISTANCE +other remailers between two occurrences of the +same remailer in the chain. Default: +.BR 2 . +.TP +.B MINREL +Only select remailers with a reliability of at least +.IR MINREL %. +Default: +.BR 98 . +.TP +.B RELFINAL +Only select a remailer with a reliability of at least +.IR RELFINAL % +as the final remailer. Default: +.BR 99 . +.TP +.B MAXLAT +Only select remailers with a latency of at most +.IR MAXLAT . +Default: +.BR 36h . +.TP +.B MINLAT +Only select remailers with a latency of at least +.IR MINLAT . +Default: +.BR 5m . +.TP +.B PGPPUBRING +Path to your public PGP key ring. Default: +.BR ~/.pgp/pubring.pkr . +(Windows default: PGP registry value.) +.TP +.B PGPSECRING +Path to your secret PGP key ring. Default: +.BR ~/.pgp/secring.skr . +(Windows default: PGP registry value.) +.TP +.B CLIENTAUTOFLUSH +If +.B REMAIL +is set to +.BR n +automatically flush the pool every time Mixmaster is run. Default: +.BR n . +.TP +.B SENDMAIL +Path to the +.BR sendmail (1) +program. If set to +.BR outfile , +Mixmaster will create text files named +.BI out * .txt +in the +.B pool +directory instead of sending mail. +Default: +.BR "/usr/lib/sendmail -t" . +.TP +.B SMTPRELAY +Name of SMTP relay. If set, mail will be delivered to the relay +rather than by +.BR sendmail (1). +.TP +.B HELONAME +Host name used in the SMTP dialogue. +Default: The +.I ENVFROM +host name or the current network name associated with the socket. +.TP +.B SMTPUSERNAME +Some mail servers require authentication for sending mail. This is +the authenticated SMTP user name. +.B SMTPPASSWORD +Password for authenticated SMTP. +.TP +.B ENVFROM +Envelope from address used in the SMTP dialogue. (When the client is +used to send non-anonymous messages, +.I ADDRESSS +is used instead.) +Default: +.IR ANONADDR . +.TP +.B ALLPINGERSURL +URL from which to download the +.IR ALLPINGERSFILE . +Default: +.BR http://www.noreply.org/allpingers/allpingers.txt . +.TP +.B WGET +Define the http protocol download tool. Default: +.BR wget . +.SS Remailer configuration: +.TP +.B NEWS +Path to the news posting program, or address of a +mail-to-news gateway. Default: no news posting. +(When using a news posting program, +.I ORGANIZATION +contains +an Organization line for anonymous messages. Default: +.BR "Anonymous Posting Service" .) +.TP +.B SENDANONMAIL +Path to a program for sending anonymous mail. Default: +.IR SENDMAIL . +.B SENDANONMAIL +can be used to invoke an external mail filter for anonymized messages. +.TP +.B SHORTNAME +A short name for the remailer to be used in lists. Defaults to the host name. +.TP +.B REMAILERADDR +The remailer mail address. +.TP +.B ANONADDR +An address to be inserted in the +.B From: +line of anonymous messages. Default: +.IR REMAILERADDR . +.TP +.B REMAILERNAME +A name to be inserted in the +.B From: +line of remailer status +messages. Default: +.BR "Anonymous Remailer" . +.TP +.B ANONNAME +A name to be inserted in the +.B From: +line of anonymous messages. +Default: +.BR "Anonymous" . +.TP +.B COMPLAINTS +An address for complaints to be sent to. Default: +.IR REMAILERADDR . +.TP +.B ERRLOG +Name of a file to log error messages, or +.B stdout +or +.BR stderr . +Default: +.BR stderr . +(When run from a tty, Mixmaster will always print a copy of error +messages to +.BR stderr .) +.TP +.B MAILBOX +A generic mail folder for non-remailer messages that are not stored in +any of the following folders. +If +.B MAILBOX +begins with a +.BR | , +it specifies the path to a program. If it contains an +.B @ +sign, the message is forwarded to the given address (with an +.B X-Loop: +header to prevent mail loops). If it ends with a +.B / +it is treated as a Maildir, otherwise the message is appended +to the given file name or written to standard output if +.B MAILBOX +is +.BR stdout . +Default: +.BR mbox . +.TP +.B MAILABUSE +Mail folder for messages sent to the +.I COMPLAINTS +address. +Default: +.IR MAILBOX . +.TP +.B MAILBLOCK +Mail folder for messages sent to the remailer address with a +.B DESTINATION-BLOCK +line. +Default: +.IR MAILBOX . +.TP +.B MAILUSAGE +Mail folder for messages sent to the remailer address that do not +contain any valid remailer commands. Default: +.BR /dev/null . +.TP +.B MAILANON +Mail folder for replies sent to the +.I ANONADDR +address. +Default: +.BR /dev/null . +.TP +.B MAILERROR +Mail folder for messages that cannot be decrypted or contain other +errors. Default: +.BR /dev/null . +.TP +.B MAILBOUNCE +Mail folder for bounce messages. Default: +.IR MAILBOX . +.TP +.B MAILIN +If defined an additional mail folder where Mixmaster should read messages from +when processing its pool. If it ends with a +.B / +it is treated as a Maildir, otherwise a standard mbox format file +is expected. All messages are removed from the folder after reading. +.B MAILIN +is not set by default. +It is an incredibly bad idea to set this the same as \fBMAILBOX\fP. +.TP +.B VERBOSE +If +.B VERBOSE +is set to +.BR 0 , +Mixmaster will log error +messages only. If it is set to +.BR 1 , +error messages and warnings are logged. If +.B VERBOSE +is set to +.BR 2 , +successful operation is logged as well. +If set to +.BR 3 , +a log file entry is created whenever a message +enters or leaves the pool. Default: +.BR 2 . +.TP +.B PASSPHRASE +A passphrase used to protect the remailer secret keys from +casual attackers. This setting overrides the compile-time +defined +.B COMPILEDPASS +which is now deprecated. +This should +.I not +be the same as the client passphrase. +.TP +.B EXTFLAGS +Additional flags you want to set in the remailer's capabilities string. +Defaults to the empty string, which means none. Example: +.BR testing . +.TP +.B PRECEDENCE +Sets the header Precedence: to this value for all outgoing mail. +Defaults to the empty string, which means no such header is added. +Example: +.BR anon . +If you use this you might want to block user supplied precedence +headers in your header block file. +.PP +The following variables can be set to +.B y +or +.BR n : +.TP +.B REMAIL +Enable remailer functionality. Default: +.BR n . +.TP +.B MIDDLEMAN +Act as an intermediate hop only, forward anonymized +messages to another remailer. This mode can be used +where complaints about anonymous messages must be +avoided. (The variable +.B FORWARDTO +specifies the remailer +chain to be used; default: +.BR * .) +Default: +.BR n . +.TP +.B AUTOREPLY +Send help files in response to non-remailer messages. Explicit +.B remailer-help +requests are always served. +Default: +.BR n . +.TP +.B MIX +Accept Mixmaster messages. Default: +.BR y . +.TP +.B PGP +Accept OpenPGP-encrypted Cypherpunk remailer messages. +Default: +.BR n . +.TP +.B UNENCRYPTED +Accept unencrypted Cypherpunk remailer messages. +Default: +.BR n . +.TP +.B REMIX +Re-encrypt Type I messages to other remailers in the Mixmaster format +.RB ( x += only when requested by user explicitly). +Default: +.BR y . +.TP +.B BINFILTER +Filter out binary attachments. Default: +.BR n . +.TP +.B LISTSUPPORTED +List known remailers and their keys in remailer-conf reply. Default: +.BR y . +.TP +.B MID +Use a hash of the message body as Message-ID, to avoid +Usenet spam. Default: +.BR y . +If +.B MID +is set to a string +beginning with +.BR @ , +that string is used as the domain part of the message ID. +.TP +.B AUTOBLOCK +Allow users to add their address to the +.B dest.blk +file by sending the remailer a message containing the line +.BR destination-block . +Default: +.BR y . +.TP +.B STATSDETAILS +List statistics on intermediate vs. final delivery in remailer-stats. +Default: +.BR y . +.PP +The following variables have numeric values: +.TP +.B POOLSIZE +The size of the Mixmaster reordering pool. Larger sizes +imply higher security and longer delays. Remailer default: +.BR 45 . +Client default: +.BR 0 . +.TP +.B RATE +Percentage of messages from the pool to be sent. Remailer default: +.BR 65 . +Client default: +.BR 100 . +Lower values cause the pool to increase in size when +many messages are received at a time, reducing the effect +of flooding attacks. +.TP +.B INDUMMYP +Probability that Mixmaster will generate dummy messages upon +receipt of incoming mail. Larger numbers mean more dummy +messages on average. For instance, +.B 10 +means that on average one in nine incoming messages will trigger +a dummy generation, and +.B 20 +means that one in four will. +.B 0 +means no dummy messages. Remailer default: +.BR 10 . +Client default: +.BR 3 . +.TP +.B OUTDUMMYP +Probability that Mixmaster will generate dummy messages at +.B SENDPOOL +time. If the pool is processed frequently, this should be a lower value +than if there are long intervals between pool processing. Examples: +.B 50 +means on average, one dummy message will be generated per pool +processing. +.B 80 +means four will be generated. +.B 0 +means no dummy messages. Remailer default: +.BR 90 . +Client default: +.BR 3 . +.TP +.B SIZELIMIT +Maximum size for anonymous messages in kB. +.B 0 +means no limit. +Default: +.BR 0 . +.TP +.B POP3SIZELIMIT +Maximum size for incoming messages in kB when using POP3. +.B 0 +means no limit. +Default: +.BR 0 . +Larger messages are deleted unread if +.B POP3DEL +is set to +.BR y , +and left on the server otherwise. +.TP +.B INFLATEMAX +Maximum size for +.B Inflate: +padding in kB. +.B 0 +means padding is not allowed. +Default: +.B 50 +.BR kB . +.TP +.B MAXRANDHOPS +Maximum chain length for message forwarding requested by +.B Rand-Hop +directives. +Default: +.BR 4 . +.TP +.B MAXRECIPIENTS +limits the number of allowed recipients in outgoing mail. Anything that exceeds this +number is dropped silently. Default: +.BR 5 . +.TP +.B TEMP_FAIL +exit with this exit code when a timeskew problem is suspected. Also see +.BR TIMESKEW_BACK +and +.BR TIMESKEW_FORWARD . +The default of +.B 75 +should cause your MTA to requeue the message if you are running +mixmaster from a +.BR .forward +file. +.TP +.B STATSAUTOUPDATE +Set non-zero to enable Daemon stats download mode. Default: +.BR 0 . +.PP +The following are time variables. They can be given as years ( +.BR y +), months ( +.BR b +), days ( +.BR d +), hours ( +.BR h +), minutes ( +.BR m +), or seconds ( +.BR s +). +.TP +.B SENDPOOLTIME +How often Mixmaster should check the pool for messages +to be sent. Remailer default: +.BR 15m . +Client default: +.BR 0h . +.TP +.B POP3TIME +How often Mixmaster should check the POP3 accounts +listed in +.B pop3.cfg +for new mail. +Default: +.BR 1h . +.TP +.B MAILINTIME +How often Mixmaster should read mail from +.BR MAILIN +and process mails fetched via POP3. Processing here means to +answer remailer-xxx requests and decrypt messages to the Mixmaster +and place them in the pool. No other processing of the pool is +done. This action is always performed sending out messages from the pool (at +.BR SENDPOOLTIME +intervals) or receiving mail via POP3 (at +.BR POP3TIME +intervals). Default: +.BR 5m . +.TP +.B PACKETEXP +How long to store parts of incomplete multipart messages and other +temporary pool files. +Default: +.BR 7d . +.TP +.B IDEXP +Mixmaster keeps a log of packet IDs to prevent replay +attacks. +.B IDEXP +specifies after which period of time old +IDs are expired. Default: +.BR 7d , +minimum: +.BR 5d . +If set to +.BR 0 , +no log is kept. +.TP +.B KEYLIFETIME +Mixmaster sets an expiration date on its remailer keys +.B KEYLIFETIME +after the key creation date. Default: +.BR 13b . +.TP +.B KEYGRACEPERIOD +Mixmaster will continue to decrypt messages encrypted to an expired key +for +.B KEYGRACEPERIOD +period of time after the expiration. This is done to ensure that messages +already injected into the network are allowed to exit. Do not change this +value unless you know what you are doing, or you will risk partitioning +attacks. Default: +.BR 7d . +.TP +.B KEYOVERLAPPERIOD +Mixmaster will generate and advertise a new key +.BR KEYOVERLAPPERIOD +period of time before the expiration of the key. Clients should always use +the most recently created valid key. Clients that deviate from this +recommended behavior risk partitioning attacks. Default: +.BR 7d . +.TP +.B TIMESKEW_BACK +Allow going back up to +.BR TIMESKEW_BACK +in time. If the time moved further back mixmaster will assume +there is a problem with your clock and refuse to start as a remailer. +This is done by comparing the latest timestamp in +.BR time.log +with the current timestamp. If set to +.BR 0 +then this test is skipped. If the system time is indeed correct, simply +remove +.BR time.log . +Default: +.BR 12h . +.TP +.B TIMESKEW_FORWARD +Similar to +.BR TIMESKEW_BACK +but allow jumping this far into the future. +Default: +.BR 2w . +.TP +.B STATSINTERVAL +Time interval between daemon downloads of stats files. Enabled by +.BR STATSAUTOUPDATE . +Default: +.BR 2h . +.PP +The following strings must be specified at compile-time in +.BR config.h . +It is not usually necessary to modify any of these: +.TP +.B +DISCLAIMER +A default string to be inserted in the header of all anonymous +messages if no +.B disclaim.txt +file is available. If +.B DISCLAIMER +contains the substring +.BR "%s" , +it will be substituted with the +.I COMPLAINTS +address. +.TP +.B FROMDISCLAIMER +A default string to be inserted at the top of the message body +if an anonymous message contains a user-supplied +.B From: +line and no +.B fromdscl.txt +file is available. +.TP +.B MSGFOOTER +A default string to be inserted at the bottom of the message body +of all anonymous messages if no +.B footer.txt +file is available. +.TP +.B BINDISCLAIMER +A string to replace the body of a binary attachment when +the remailer is configured to filter out binaries. +.TP +.B CHARSET +The character set used for MIME-encoded header lines. +.TP +.B DESTBLOCK +A quoted list of files that contain blocked addresses. +Files must be separated by one space. Mixmaster will choose +the first file for writing if +.B AUTOBLOCK +is enabled. +.PP +The following variables can be set in the +.B Makefile +or in +.BR config.h : +.TP +.B COMPILEDPASS +A passphrase used to protect the remailer secret keys from +casual attackers. You can use +.B `make PASS="\fIyour passphrase\fB"' +to set a passphrase. This should +.I not +be the same as the client passphrase. This option is now deprecated in +favor of the configuration file option +.BR PASSPHRASE . +.TP +.B SPOOL +Set +.B SPOOL +if you want to use a default directory other than +.B ~/Mix +or if Mixmaster is run in an environment where +.B $HOME +is not set, e.g. when invoked via +.BR .forward . +This value can be overridden by use of the environment variable +.BR $MIXPATH . +.TP +.B USE_SSLEAY +Use the SSLeay/OpenSSL cryptographic library. Currently this is the +only cryptographic library supported by Mixmaster. +.TP +.B USE_IDEA +Use the IDEA encryption algorithm. A license is required to use IDEA +for commercial purposes. See file +.B idea.txt +for details. +.TP +.B USE_PGP +Support the OpenPGP encryption format. Mixmaster does not call any +external encryption program. +.TP +.B USE_PCRE +Use the regular expression library. +.TP +.B USE_ZLIB +Use the +.B zlib +compression library. +.TP +.B USE_NCURSES +Use the +.B ncurses +library. +.TP +.B USE_SOCK +Use sockets to transfer mail by POP3 and SMTP. +.TP +.B USE_WINGUI +Use the +.B Win32 +GUI. +.TP +.B HAVE_GETDOMAINNAME +The +.BR getdomainname (2) +function is available. +.SH FILES +These filenames can be overridden by setting the corresponding configuration +option (given in parentheses). +.TP +.B mix.cfg +Mixmaster configuration file. +.TP +.B pubring.asc +Type 1 remailer keys (\fBPGPREMPUBASC\fP). +.TP +.B pubring.mix +Type 2 remailer keys (\fBPUBRING\fP). +.TP +.B rlist.txt +List of reliable type 1 remailers (\fBTYPE1LIST\fP). +.TP +.B mlist.txt +List of reliable type 2 remailers (\fBTYPE2REL\fP). +.TP +.B type2.list +List of known type 2 remailers (optional) (\fBTYPE2LIST\fP). +.TP +.B starex.txt +List of remailers which should not be used in randomly generated +remailer chains (\fBSTAREX\fP). +.SS Remailer files: +.TP +.B disclaim.txt +A string to be inserted in the header of all anonymous +messages (\fBDISCLAIMFILE\fP). +.TP +.B fromdscl.txt +A string to be inserted at the top of the message body +if an anonymous message contains a user-supplied +.B From: +line (\fBFROMDSCLFILE\fP). +.TP +.TP +.B footer.txt +A string to be inserted at the bottom of the message body +of all anonymous messages (\fBMSGFOOTERFILE\fP). +.TP +.B help.txt +Help file sent in response to +.B remailer-help +requests (\fBHELPFILE\fP). +.TP +.B adminkey.txt +The PGP key of the remailer operator sent in response to +.B remailer-adminkey +requests (\fBADMKEYFILE\fP). +.TP +.B abuse.txt +File sent in response to mail to the +.I COMPLAINTS +address if +.B AUTOREPLY +is set (\fBABUSEFILE\fP). +.TP +.B reply.txt +Help file sent in response to replies to anonymous messages if +.B AUTOREPLY +is set (\fBREPLYFILE\fP). +.TP +.B usage.txt +Help file sent in response to non-remailer message sent to +.I REMAILERADDR +if +.B AUTOREPLY +is set. If +.B usage.log +exists, recipients are logged and a reply is sent only once to avoid +mail loops (\fBUSAGEFILE\fP). +.TP +.B blocked.txt +Information sent in response to automatically processed blocking requests if +.B AUTOREPLY +is set (\fBBLOCKFILE\fP). +.TP +.B pop3.cfg +List of POP3 accounts with lines of the form +.I account@host.domain password +to get remailer messages from. The lines may optionally contain the +keyword "apop" or "pass" to select an authentication method (\fBPOP3CONF\fP). +.TP +.B dest.alw +List of addresses to which Mixmaster will deliver, even in middleman mode (\fBDESTALLOW\fP). +.TP +.B dest.alw.nonpublished +Similar to +.BR dest.alw , +with the only difference that this list is not published in remailer-conf replies (\fBDESTALLOW2\fP). +.TP +.B dest.blk +List of blocked destination addresses. +Mixmaster does not send mail to the blocked addresses listed in this file (\fBDESTBLOCK\fP). +.TP +.B rab.blk +Identical to +.BR dest.blk , +except Mixmaster will not write to this file. +For use with external remailer abuse blocklists. +.TP +.B source.blk +List of blocked source addresses. If an incoming message originates +from an address or IP in this list, it will be ignored. This +feature can be used to avoid spam and other abusive mail (\fBSOURCEBLOCK\fP). +.TP +.B header.blk +List of unwanted header fields. The file is used to delete unwanted +header lines (e.g. lines that indicate a false identity, or Usenet +control messages), and do other header filtering (\fBHDRFILTER\fP). + +A destination address or header line is left out if it contains a +search string or matches a regular expression specified in the block +file. Lines in the block file that begin and end with a slash +.RB ( /\fIregexp\fB/ ) +are interpreted as regular expressions. Lines without +slashes are used for case-independent substring search. + +If a message contains a header line that matches a +.B /\fIregexp\fB/q +entry in +.BR header.blk , +the entire message is deleted. + +In addition, regular expressions can be substituted. Back-references +are supported. For example + + /^From: *([^@]*) <.*>/From: $1/ + /^From:.* \\(([^@]*)\)/From: $1/ + /^From: *([^@]*).*$/From: $1 <\fInobody@remailer.domain\fR>/ + +would allow user-defined names in the +.B From: +line, while replacing any given address with the remailer address. +.TP +.B allpingers.txt +Information on all known pingers (\fBALLPINGERSFILE\fP). +.SS +Mixmaster uses the following files internally: +.TP +.B mixrand.bin +Random seed file (\fBMIXRAND\fP). +.TP +.B secring.pgp +Remailer type 1 secret keys (\fBPGPREMSECRING\fP). +.TP +.B secring.mix +Remailer type 2 secret keys (\fBSECRING\fP). +.TP +.B pgpkey.txt +The public type 1 remailer key (\fBPGPKEY\fP). +.TP +.B key.txt +The public type 2 remailer key (\fBKEYFILE\fP). +.TP +.B id.log +Log file of messages already processed (\fBIDLOG\fP). +.TP +.B stats.log +Log file for remailer statistics (\fBSTATS\fP). +.TP +.B stats-src.txt +File for name of most recent statistics source (\fBSTATSSRC\fP). +.TP +.B pgpmaxcount.log +Log file for PGP Max-Count statistics (\fBPGPMAXCOUNT\fP). +.TP +.B time.log +Time for periodic remailer actions (\fBREGULAR\fP). +.TP +.B dhparam.mix +Public Diffie-Hellman parameters used for El-Gamal key generation (\fBDHPARAMS\fP). +.TP +.B dsaparam.mix +Public DSA parameters used for DSA key generation (\fBDSAPARAMS\fP). +.TP +.B mixmaster.pid +Pid file in daemon mode (\fBPIDFILE\fP). +.TP +.BI pool/ +Message pool directory (\fBPOOL\fP). +.TP +.BI pool/m * +Message pool files. +.TP +.BI pool/p * +Partial messages. +.TP +.BI pool/l * +Latent messages. +.TP +.BI pool/s * +Messages to be sent. +.TP +.BI pool/t * +Temporary files. +.SH ENVIRONMENT +.TP +.I MIXPATH +The path to the Mixmaster directory. The default is +.BR ~/Mix . +.TP +.I MIXPASS +The passphrase used to protect your nyms and PGP keys. +(The remailer uses a different passphrase.) If +.I MIXPASS +is not set, the client will ask for a passphrase. +.SH SEE ALSO +.BR mpgp (1), +.BR pgp (1), +.BR procmail (1), +.BR sendmail (8). +.SH HISTORY +Mixmaster is an implementation of a Chaumian mix-net system. +Versions 1.0 through 2.0.3 of the +.BR mixmaster +remailer were originally written by Lance Cottrell. Mixmaster was first +released in 1995. Ulf Moeller collaborated on version 2.0.4, and began an +entire rewrite of +.BR mixmaster +in 1999. This rewrite was released in 2002 as version 2.9.0, with major +contributions from Janis Jagars, Peter Palfrader, and Len Sassaman. +Mixmaster 3.0 is based on the 2.9 codebase. Peter Palfrader and Len +Sassaman were the principal maintainers until 2006. Since then, Steve +Crook, Len Sassaman, and Colin Tuckley have filled the role of +principal maintaners. For more information on contributing authors, +please see the file THANKS for details. +.SH COPYRIGHT +Copyright 1999 - 2008 Anonymizer Inc., The Mixmaster Development Team, +and others. + +Mixmaster may be redistributed and modified under certain conditions. +This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +ANY KIND, either express or implied. See the file COPYRIGHT for +details. diff --git a/mpgp.1 b/mpgp.1 @@ -0,0 +1,121 @@ +.TH MPGP 1 "Mixmaster Version 3.0" +.\" $Id: $ +.SH NAME +mpgp \- Mixmaster OpenPGP Module +.SH SYNOPSIS +.B mpgp \fB\-e\fR [\fB\-b\fR] \fIkeyname\fR [\fIfilename\fR] +.PP +.B mpgp \fB\-s\fR [\fB\-b\fR] [\fIkeyname\fR [\fIfilename\fR]] +.PP +.B mpgp \fB\-c\fR [\fB\-b\fR] [\fIfilename\fR] +.PP +.B mpgp \fB\-C\fR [\fB\-b\fR] [\fIfilename\fR] +.PP +.B mpgp \fB\-d\fR [\fB\-b\fR] [\fIpassphrase\fR [\fIfilename\fR]] +.PP +.B mpgp \fB\-g\fR[\fBr\fR] \fIkeyname\fR [\fIbits\fR] +.PP +.B mpgp \fB\-a\fR[\fB+\-\fR] [\fB\-b\fR] [\fIfilename\fR] +.PP +.B mpgp \fB\-V\fR +.SH DESCRIPTION +Mixmaster is an anonymous remailer. mpgp is a light-weight OpenPGP +implementation, primarily used to diagnose issues with OpenPGP keys and +messages handled by the Mixmaster remailer software. +.PP +mpgp can encrypt, decrypt and sign a message using the Mixmaster +OpenPGP library. The message is read from the standard input or the +specified \fIfilename\fR. The output will be written to the standard +output. When called without arguments mpgp decrypts from the standard +input. It asks for a passphrase when needed. +.SH OPTIONS +.TP +.B "\-h" +Print a summary of command line options. +.TP +.B "\-V" +Print the current version, authorship and copyright information. +.TP +.B "\-e" +Encrypt a message with the first OpenPGP key from the public key ring +whose contains \fIkeyname\fR as a substring. +.TP +.B "\-s" +Make a signature of the message with the first OpenPGP key from the secret +key ring, or the first key whose contains \fIkeyname\fR as a substring if +specified. +.TP +.B "\-c" +Encrypt with symmetric cipher only. +.TP +.B "\-C" +Encrypt with symmetric cipher only using the new OpenPGP format. +.TP +.B "\-d" +Decrypt a message using \fIpassphrase\fR if specified or asking for it if +needed. It also verifies its signature. +.TP +.B "\-g\fR[\fBr\fR]" +Generate new OpenPGP key pair with the given \fIkeyname\fR as user ID. If +\fBr\fR is specified the OpenPGP key will be created using the RSA +algorithm, otherwise the ElGamal algorithm will be used. \fIbits\fR is the +key length and its default value is 1024. +.TP +.B "\-a\fR[\fB+\-\fR]" +Create an ASCII OpenPGP armored message. If \fB\-\fR is specified mpgp +will remove ASCII armor. +.TP +.B "\-b" +Specifies that the message is in binary format. +.SH CONFIGURATION +The Mixmaster OpenPGP module reads its configuration from the file +.B mix.cfg +in its working directory. The configuration file consists of lines of +the type +.PP +.I VARIABLE values +.PP +and of comments, which begin with a +.B # +character. +.PP +.TP +.B PGPPUBRING +Path to your public OpenPGP key ring. Default: +.BR ~/.pgp/pubring.pgp . +(Windows default: PGP registry value.) +.TP +.B PGPSECRING +Path to your secret OpenPGP key ring. Default: +.BR ~/.pgp/secring.pgp . +(Windows default: PGP registry value.) +.SH FILES +These filenames can be overridden by setting the corresponding configuration +option (given in parentheses). +.TP +.B mix.cfg +Mixmaster configuration file. +.TP +.B pubring.pgp +OpenPGP public keys (\fBPGPPUBRING\fP). +.TP +.B secring.pgp +OpenPGP secret keys (\fBPGPSECRING\fP). +.SH SEE ALSO +.BR mixmaster (1), +.BR pgp (1), +.BR gpg (1). +.SH HISTORY +The +.BR mpgp +command was written by Ulf Moeller as a test suite for Mixmaster +2.9's internal OpenPGP support. It was enhanced and debugged primarily +by Janis Jagars for use as a light-weight stand-alone OpenPGP application. +.SH COPYRIGHT +(C) 1999-2006 Ulf Moeller and others. +Mixmaster and +.BR mpgp +may be redistributed and modified under certain +conditions. This software is distributed on an "AS IS" basis, WITHOUT +WARRANTY OF ANY KIND, either express or implied. See the file COPYRIGHT +for details. diff --git a/win32/installer/mixinstall.nsi b/win32/installer/mixinstall.nsi @@ -0,0 +1,70 @@ +Name "Mixmaster" + +OutFile "Mixmaster-Setup.exe" + +InstallDir $PROGRAMFILES\Mixmaster + +; Registry key to check for directory (so if you install again, it will +; overwrite the old one automatically) +InstallDirRegKey HKLM "Software\Mixmaster" "Install_Dir" + +;-------------------------------- + +; Pages + +Page components +Page directory +Page instfiles + +UninstPage uninstConfirm +UninstPage instfiles + +;-------------------------------- + +Section "Mixmaster" + SectionIn RO + SetOutPath $INSTDIR + File "..\release\mix.exe" + File "..\release\mixlib.dll" + File "..\..\Src\openssl\out32dll\libeay32.dll" + File "c:\winnt\system32\msvcr71.dll" + + WriteRegStr HKLM SOFTWARE\Mixmaster "Install_Dir" "$INSTDIR" + + ; Write the uninstall keys for Windows + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mixmaster" "DisplayName" "Mixmaster" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mixmaster" "UninstallString" '"$INSTDIR\uninstall.exe"' + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mixmaster" "NoModify" 1 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mixmaster" "NoRepair" 1 + WriteUninstaller "uninstall.exe" +SectionEnd + +Section "Start Menu Shortcuts (All Users)" + SetShellVarContext all + CreateDirectory "$SMPROGRAMS\Mixmaster" + CreateShortCut "$SMPROGRAMS\Mixmaster\Mixmaster.lnk" "$INSTDIR\mix.exe" "" "$INSTDIR\mix.exe" 0 + CreateShortCut "$SMPROGRAMS\Mixmaster\Uninstall Mixmaster.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 +SectionEnd + +Section "Create Desktop Item (All Users)" + SetShellVarContext all + CreateShortCut "$DESKTOP\Mixmaster.lnk" "$INSTDIR\mix.exe" "" "$INSTDIR\mix.exe" 0 +SectionEnd + +Section "Uninstall" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mixmaster" + DeleteRegKey HKLM SOFTWARE\Mixmaster + + Delete $INSTDIR\mix.exe + Delete $INSTDIR\mixlib.dll + Delete $INSTDIR\libeay32.dll + Delete $INSTDIR\msvcr71.dll + Delete $INSTDIR\uninstall.exe + + SetShellVarContext all + Delete "$SMPROGRAMS\Mixmaster\*.*" + RMDir "$SMPROGRAMS\Mixmaster" + Delete "$DESKTOP\Mixmaster.lnk" + + RMDir "$INSTDIR" +SectionEnd diff --git a/win32/mix.sln b/win32/mix.sln @@ -0,0 +1,79 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mix", "mix.vcproj", "{075AD568-26A6-4C0F-9D78-60E6BA2FD7CC}" + ProjectSection(ProjectDependencies) = postProject + {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844} = {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mixlib", "mixlib.vcproj", "{BE1E2A5D-7460-4F06-AEEB-9443B1EE1844}" + ProjectSection(ProjectDependencies) = postProject + {FC9B2030-6750-4272-87C9-6E46AB029F69} = {FC9B2030-6750-4272-87C9-6E46AB029F69} + {F587947F-949D-4AD6-A527-3A34918741B5} = {F587947F-949D-4AD6-A527-3A34918741B5} + {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174} = {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcre", "Pcre.vcproj", "{FC9B2030-6750-4272-87C9-6E46AB029F69}" + ProjectSection(ProjectDependencies) = postProject + {63F7F010-3302-4329-A9AC-9739FC57EC51} = {63F7F010-3302-4329-A9AC-9739FC57EC51} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcre_chartables", "Pcre_Chartables.vcproj", "{63F7F010-3302-4329-A9AC-9739FC57EC51}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib.vcproj", "{6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pdcurses", "pdcurses.vcproj", "{F587947F-949D-4AD6-A527-3A34918741B5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + Release Static = Release Static + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {075AD568-26A6-4C0F-9D78-60E6BA2FD7CC}.Debug.ActiveCfg = Release Static|Win32 + {075AD568-26A6-4C0F-9D78-60E6BA2FD7CC}.Debug.Build.0 = Release Static|Win32 + {075AD568-26A6-4C0F-9D78-60E6BA2FD7CC}.Release.ActiveCfg = Release|Win32 + {075AD568-26A6-4C0F-9D78-60E6BA2FD7CC}.Release.Build.0 = Release|Win32 + {075AD568-26A6-4C0F-9D78-60E6BA2FD7CC}.Release Static.ActiveCfg = Release Static|Win32 + {075AD568-26A6-4C0F-9D78-60E6BA2FD7CC}.Release Static.Build.0 = Release Static|Win32 + {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844}.Debug.ActiveCfg = Release|Win32 + {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844}.Debug.Build.0 = Release|Win32 + {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844}.Release.ActiveCfg = Release|Win32 + {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844}.Release.Build.0 = Release|Win32 + {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844}.Release Static.ActiveCfg = Release|Win32 + {BE1E2A5D-7460-4F06-AEEB-9443B1EE1844}.Release Static.Build.0 = Release|Win32 + {FC9B2030-6750-4272-87C9-6E46AB029F69}.Debug.ActiveCfg = Release|Win32 + {FC9B2030-6750-4272-87C9-6E46AB029F69}.Debug.Build.0 = Release|Win32 + {FC9B2030-6750-4272-87C9-6E46AB029F69}.Release.ActiveCfg = Release|Win32 + {FC9B2030-6750-4272-87C9-6E46AB029F69}.Release.Build.0 = Release|Win32 + {FC9B2030-6750-4272-87C9-6E46AB029F69}.Release Static.ActiveCfg = Release|Win32 + {FC9B2030-6750-4272-87C9-6E46AB029F69}.Release Static.Build.0 = Release|Win32 + {63F7F010-3302-4329-A9AC-9739FC57EC51}.Debug.ActiveCfg = Release|Win32 + {63F7F010-3302-4329-A9AC-9739FC57EC51}.Debug.Build.0 = Release|Win32 + {63F7F010-3302-4329-A9AC-9739FC57EC51}.Release.ActiveCfg = Release|Win32 + {63F7F010-3302-4329-A9AC-9739FC57EC51}.Release.Build.0 = Release|Win32 + {63F7F010-3302-4329-A9AC-9739FC57EC51}.Release Static.ActiveCfg = Release|Win32 + {63F7F010-3302-4329-A9AC-9739FC57EC51}.Release Static.Build.0 = Release|Win32 + {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174}.Debug.ActiveCfg = Release|Win32 + {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174}.Debug.Build.0 = Release|Win32 + {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174}.Release.ActiveCfg = Release|Win32 + {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174}.Release.Build.0 = Release|Win32 + {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174}.Release Static.ActiveCfg = Release|Win32 + {6A9ECAB3-1CA6-4E2A-8A15-F8AE459BB174}.Release Static.Build.0 = Release|Win32 + {F587947F-949D-4AD6-A527-3A34918741B5}.Debug.ActiveCfg = Release|Win32 + {F587947F-949D-4AD6-A527-3A34918741B5}.Debug.Build.0 = Release|Win32 + {F587947F-949D-4AD6-A527-3A34918741B5}.Release.ActiveCfg = Release|Win32 + {F587947F-949D-4AD6-A527-3A34918741B5}.Release.Build.0 = Release|Win32 + {F587947F-949D-4AD6-A527-3A34918741B5}.Release Static.ActiveCfg = Release|Win32 + {F587947F-949D-4AD6-A527-3A34918741B5}.Release Static.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/win32/mix.vcproj b/win32/mix.vcproj @@ -0,0 +1,193 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="mix" + SccProjectName="" + SccLocalPath=""> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\mix_intermediate" + ConfigurationType="1" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + AdditionalIncludeDirectories="../Src/openssl/inc32" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_WIN32;IBMPC_SYSTEM;_MSC;MSC" + StringPooling="TRUE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="TRUE" + PrecompiledHeaderFile=".\mix_intermediate/mix.pch" + AssemblerListingLocation=".\mix_intermediate/" + ObjectFile=".\mix_intermediate/" + ProgramDataBaseFileName=".\mix_intermediate/" + WarningLevel="3" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wsock32.lib" + OutputFile=".\Release/mix.exe" + LinkIncremental="1" + SuppressStartupBanner="TRUE" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool" + PreprocessorDefinitions="NDEBUG" + MkTypLibCompatible="TRUE" + SuppressStartupBanner="TRUE" + TargetEnvironment="1" + TypeLibraryName=".\Release/mix.tlb" + HeaderFileName=""/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release Static|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\mix_Release" + ConfigurationType="1" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + AdditionalIncludeDirectories="../../src/zlib-1.1.4,../../src/pcre-2.08" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_WIN32;IBMPC_SYSTEM;_MSC;MSC" + StringPooling="TRUE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="TRUE" + PrecompiledHeaderFile=".\mix_Release/mix.pch" + AssemblerListingLocation=".\mix_Release/" + ObjectFile=".\mix_Release/" + ProgramDataBaseFileName=".\mix_Release/" + WarningLevel="3" + SuppressStartupBanner="TRUE" + CompileAs="0"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wsock32.lib libeay32.lib $(OutDir)\pcre.lib $(OutDir)\zlib.lib $(OutDir)\mixlib_static.lib" + OutputFile=".\Release/mix.exe" + LinkIncremental="1" + SuppressStartupBanner="TRUE" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool" + PreprocessorDefinitions="NDEBUG" + MkTypLibCompatible="TRUE" + SuppressStartupBanner="TRUE" + TargetEnvironment="1" + TypeLibraryName=".\Release/mix.tlb" + HeaderFileName=""/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="..\Src\main.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Release Static|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\service.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Release Static|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl"> + </Filter> + <Filter + Name="Resource Files" + Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/win32/mixlib.vcproj b/win32/mixlib.vcproj @@ -0,0 +1,459 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="mixlib" + SccProjectName="" + SccLocalPath=""> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\mixlib_intermediate" + ConfigurationType="2" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + AdditionalIncludeDirectories="&quot;../src/pcre-2.08&quot;;../Src/openssl/inc32;&quot;../src/zlib-1.1.4&quot;;../src/pdcurses" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_WIN32;IBMPC_SYSTEM;_MSC;MSC" + StringPooling="TRUE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="TRUE" + PrecompiledHeaderFile=".\mixlib_intermediate/mixlib.pch" + AssemblerListingLocation=".\mixlib_intermediate/" + ObjectFile=".\mixlib_intermediate/" + ProgramDataBaseFileName=".\mixlib_intermediate/" + WarningLevel="3" + SuppressStartupBanner="TRUE" + CompileAs="0"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wsock32.lib ../src/openssl/out32dll/libeay32.lib release/pdcurses.lib" + OutputFile=".\Release/mixlib.dll" + LinkIncremental="1" + SuppressStartupBanner="TRUE" + ModuleDefinitionFile="..\Src\mixlib.def" + ImportLibrary=".\Release/mixlib.lib" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool" + PreprocessorDefinitions="NDEBUG" + MkTypLibCompatible="TRUE" + SuppressStartupBanner="TRUE" + TargetEnvironment="1" + TypeLibraryName=".\Release/mixlib.tlb" + HeaderFileName=""/> + <Tool + Name="VCPostBuildEventTool" + Description="Build static library" + CommandLine="lib.exe /nologo /out:&quot;$(OutDir)&quot;\mixlib_static.lib &quot;$(IntDir)&quot;\*.obj"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="..\Src\buffers.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\chain.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\chain1.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\chain2.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\compress.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\crypto.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\dllmain.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\keymgt.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\mail.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\maildir.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\menu.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\menunym.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\menusend.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\menustats.c"> + </File> + <File + RelativePath="..\Src\menuutil.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\mime.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\mix.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\mixlib.def"> + </File> + <File + RelativePath="..\Src\nym.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\parsedate.tab.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pgp.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pgpcreat.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pgpdata.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pgpdb.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pgpget.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pool.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\random.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\rem.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\rem1.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\rem2.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\rfc822.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\rndseed.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\stats.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\util.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="_USRDLL;MIXLIB_EXPORTS;WIN32;NDEBUG;_WINDOWS;_MBCS;_WIN32;IBMPC_SYSTEM;_MSC;MSC;$(NoInherit)"/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl"> + <File + RelativePath="..\Src\config.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/win32/pcre.vcproj b/win32/pcre.vcproj @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="pcre" + SccProjectName="" + SccLocalPath=""> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\pcre_intermediate" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="TRUE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="TRUE" + PrecompiledHeaderFile=".\pcre_intermediate/pcre.pch" + AssemblerListingLocation=".\pcre_intermediate/" + ObjectFile=".\pcre_intermediate/" + ProgramDataBaseFileName=".\pcre_intermediate/" + WarningLevel="3" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\Release\pcre.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="..\Src\pcre-2.08\get.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pcre-2.08\maketables.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pcre-2.08\pcre.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pcre-2.08\study.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/win32/pcre_chartables.vcproj b/win32/pcre_chartables.vcproj @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="pcre_chartables" + SccProjectName="" + SccLocalPath=""> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory=".\../src/pcre-2.08" + IntermediateDirectory=".\chartables_intermediate" + ConfigurationType="1" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + StringPooling="TRUE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="TRUE" + PrecompiledHeaderFile=".\chartables_intermediate/pcre_chartables.pch" + AssemblerListingLocation=".\chartables_intermediate/" + ObjectFile=".\chartables_intermediate/" + ProgramDataBaseFileName=".\chartables_intermediate/" + WarningLevel="3" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + OutputFile="../src/pcre-2.08/dftables.exe" + LinkIncremental="1" + SuppressStartupBanner="TRUE" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool" + TypeLibraryName=".\../src/pcre-2.08/pcre_chartables.tlb" + HeaderFileName=""/> + <Tool + Name="VCPostBuildEventTool" + Description="Creating chartables.c" + CommandLine="&quot;$(TargetDir)&quot;dftables.exe &gt; &quot;$(TargetDir)&quot;chartables.c"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="..\Src\pcre-2.08\dftables.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl"> + </Filter> + <Filter + Name="Resource Files" + Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/win32/pdcurses.vcproj b/win32/pdcurses.vcproj @@ -0,0 +1,607 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="pdcurses" + ProjectGUID="{F587947F-949D-4AD6-A527-3A34918741B5}" + SccProjectName="" + SccLocalPath=""> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\pdcurses_intermediate" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + AdditionalIncludeDirectories="../src/pdcurses" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB;PDC_STATIC_BUILD" + StringPooling="TRUE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="TRUE" + PrecompiledHeaderFile=".\pdcurses_intermediate/pdcurses.pch" + AssemblerListingLocation=".\pdcurses_intermediate/" + ObjectFile=".\pdcurses_intermediate/" + ProgramDataBaseFileName=".\pdcurses_intermediate/" + WarningLevel="3" + SuppressStartupBanner="TRUE" + CompileAs="0"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\Release\pdcurses.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="..\Src\pdcurses\pdcurses\addch.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\addchstr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\addstr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\attr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\beep.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\bkgd.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\border.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\clear.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\color.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\delch.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\deleteln.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\getch.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\getstr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\getyx.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\inch.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\inchstr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\initscr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\inopts.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\insch.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\insstr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\instr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\kernel.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\mouse.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\move.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\outopts.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\overlay.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\pad.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdcclip.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\pdcdebug.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdcdisp.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdcgetsc.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdckbd.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdcprint.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdcscrn.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdcsetsc.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\win32\pdcurses.rc"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="" + AdditionalIncludeDirectories="\Mixmaster\trunk\Mix\Src\pdcurses\win32"/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\pdcutil.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\pdcwin.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\printw.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\refresh.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\scanw.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\scroll.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\slk.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\termattr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\terminfo.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\touch.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\util.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\pdcurses\pdcurses\window.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/win32/zlib.vcproj b/win32/zlib.vcproj @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="zlib" + SccProjectName="" + SccLocalPath=""> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\zlib_intermediate" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="TRUE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="TRUE" + PrecompiledHeaderFile=".\zlib_intermediate/zlib.pch" + AssemblerListingLocation=".\zlib_intermediate/" + ObjectFile=".\zlib_intermediate/" + ProgramDataBaseFileName=".\zlib_intermediate/" + WarningLevel="3" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\Release\zlib.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="..\Src\zlib-1.1.4\adler32.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\compress.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\crc32.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\deflate.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\gzio.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\infblock.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\infcodes.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\inffast.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\inflate.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\inftrees.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\infutil.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\trees.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\uncompr.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\Src\zlib-1.1.4\zutil.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject>