commit 50de79fe7f9e194b5a6bdd3a63fb3bdb455588a8
Author: parazyd <parazyd@dyne.org>
Date: Thu, 15 Sep 2016 01:44:49 +0200
initial sources import
Diffstat:
A | BUILD.Win32 | | | 30 | ++++++++++++++++++++++++++++++ |
A | COPYRIGHT | | | 134 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | HISTORY | | | 502 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Install | | | 1403 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | README | | | 191 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/Makefile.deps | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/Makefile.in | | | 83 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/buffers.c | | | 816 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/chain.c | | | 384 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/chain1.c | | | 301 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/chain2.c | | | 685 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/compress.c | | | 210 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/config.h | | | 403 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/crypto.c | | | 492 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/crypto.h | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/dllmain.c | | | 35 | +++++++++++++++++++++++++++++++++++ |
A | Src/dummy.c | | | 16 | ++++++++++++++++ |
A | Src/keymgt.c | | | 434 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mail.c | | | 898 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/maildir.c | | | 323 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/main.c | | | 820 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menu.c | | | 1003 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menu.h | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menunym.c | | | 472 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menusend.c | | | 556 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menustats.c | | | 445 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menuutil.c | | | 154 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mime.c | | | 814 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mix.c | | | 1262 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mix.h | | | 917 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mix3.h | | | 443 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mixlib.def | | | 121 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mpgp.c | | | 264 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/nym.c | | | 669 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/parsedate.y | | | 879 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgp.c | | | 494 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgp.h | | | 189 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpcreat.c | | | 848 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpdata.c | | | 1539 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpdb.c | | | 583 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpget.c | | | 870 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pool.c | | | 981 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/random.c | | | 210 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rem.c | | | 709 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rem1.c | | | 599 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rem2.c | | | 486 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/remailer.c | | | 36 | ++++++++++++++++++++++++++++++++++++ |
A | Src/rfc822.c | | | 585 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rndseed.c | | | 157 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/service.c | | | 331 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/stats.c | | | 442 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/tests/test-parse_yearmonthday.c | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/util.c | | | 704 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/version.h | | | 1 | + |
A | THANKS | | | 102 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | TODO | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/abuse.txt.in | | | 99 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/adminkey.txt | | | 1 | + |
A | conf/blocked.txt.in | | | 20 | ++++++++++++++++++++ |
A | conf/dest.alw | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | conf/dest.blk | | | 2 | ++ |
A | conf/end.hlp | | | 36 | ++++++++++++++++++++++++++++++++++++ |
A | conf/header.blk | | | 22 | ++++++++++++++++++++++ |
A | conf/intro.hlp | | | 15 | +++++++++++++++ |
A | conf/mix.cfg | | | 14 | ++++++++++++++ |
A | conf/mix.cfg.ex | | | 192 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/mix.hlp | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/mlist.txt | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/news.hlp | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pgp.hlp | | | 143 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pgponly.hlp | | | 144 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pubring.asc | | | 544 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pubring.mix | | | 384 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/rab.blk | | | 0 | |
A | conf/reply.txt.in | | | 32 | ++++++++++++++++++++++++++++++++ |
A | conf/rlist.txt | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/type1.hlp | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/usage.txt.in | | | 24 | ++++++++++++++++++++++++ |
A | idea.txt | | | 34 | ++++++++++++++++++++++++++++++++++ |
A | mixmaster.1 | | | 1136 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | mpgp.1 | | | 121 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/installer/mixinstall.nsi | | | 70 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/mix.sln | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/mix.vcproj | | | 193 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/mixlib.vcproj | | | 459 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/pcre.vcproj | | | 117 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/pcre_chartables.vcproj | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/pdcurses.vcproj | | | 607 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/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, ®sw);
+ len=sizeof(line);
+ if (err == -1 &&
+ RegOpenKeyEx(regsw, "Mixmaster", 0, KEY_QUERY_VALUE, ®) == 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, ®pgp) == 0)
+ rkey++;
+ if (rkey && RegOpenKeyEx(regpgp, "PGPlib", 0, KEY_QUERY_VALUE, ®) == 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(×truct, 0, sizeof(timestruct));
+ timestruct.tm_mday = day;
+ timestruct.tm_mon = month - 1;
+ timestruct.tm_year = year - 1900;
+ date = mktime(×truct);
+#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(×truct, 0, sizeof(timestruct));
+ timestruct.tm_mday = day;
+ timestruct.tm_mon = month - 1;
+ timestruct.tm_year = year - 1900;
+ date = mktime(×truct);
+#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=""../src/pcre-2.08";../Src/openssl/inc32;"../src/zlib-1.1.4";../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:"$(OutDir)"\mixlib_static.lib "$(IntDir)"\*.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=""$(TargetDir)"dftables.exe > "$(TargetDir)"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>