mixmaster-3.0/0000755000176200017620000000000010763041472013557 5ustar rabbirabbi00000000000000mixmaster-3.0/BUILD.Win320000644000176200017620000000157110672232201015235 0ustar rabbirabbi00000000000000Mixmaster 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 mixmaster-3.0/idea.txt0000644000176200017620000000351407367732047015240 0ustar rabbirabbi00000000000000This 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. mixmaster-3.0/HISTORY0000644000176200017620000007211410763042045014645 0ustar rabbirabbi00000000000000 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 ). 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 . 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 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- to remailer- 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 . 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 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. mixmaster-3.0/mpgp.10000644000176200017620000000705210447242033014603 0ustar rabbirabbi00000000000000.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. mixmaster-3.0/win32/0000755000176200017620000000000010763041471014520 5ustar rabbirabbi00000000000000mixmaster-3.0/win32/mix.vcproj0000644000176200017620000001231010044546317016540 0ustar rabbirabbi00000000000000 mixmaster-3.0/win32/zlib.vcproj0000644000176200017620000001251710044546317016714 0ustar rabbirabbi00000000000000 mixmaster-3.0/win32/pcre_chartables.vcproj0000644000176200017620000000522110044546317021067 0ustar rabbirabbi00000000000000 mixmaster-3.0/win32/mixlib.vcproj0000644000176200017620000003513010050677500017230 0ustar rabbirabbi00000000000000 mixmaster-3.0/win32/mix.sln0000644000176200017620000001142010046043304016020 0ustar rabbirabbi00000000000000Microsoft 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 mixmaster-3.0/win32/pdcurses.vcproj0000644000176200017620000003774710044601331017604 0ustar rabbirabbi00000000000000 mixmaster-3.0/win32/pcre.vcproj0000644000176200017620000000556210044546317016707 0ustar rabbirabbi00000000000000 mixmaster-3.0/win32/installer/0000755000176200017620000000000010763041471016515 5ustar rabbirabbi00000000000000mixmaster-3.0/win32/installer/mixinstall.nsi0000644000176200017620000000430410046043304021404 0ustar rabbirabbi00000000000000Name "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 mixmaster-3.0/TODO0000644000176200017620000000600310763033773014253 0ustar rabbirabbi00000000000000Items 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) mixmaster-3.0/conf/0000755000176200017620000000000010763041471014503 5ustar rabbirabbi00000000000000mixmaster-3.0/conf/mix.hlp0000644000176200017620000000341310720307525016004 0ustar rabbirabbi00000000000000This 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 **** mixmaster-3.0/conf/adminkey.txt0000644000176200017620000000005007367732047017054 0ustar rabbirabbi00000000000000Remailer Administrator's key goes here. mixmaster-3.0/conf/dest.alw0000644000176200017620000000143010720247556016152 0ustar rabbirabbi00000000000000## 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$/ mixmaster-3.0/conf/abuse.txt.in0000644000176200017620000001014307711670474016761 0ustar rabbirabbi00000000000000Thank 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 mixmaster-3.0/conf/type1.hlp0000644000176200017620000001042007405521034016244 0ustar rabbirabbi00000000000000This 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 : ================================================================== 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 ================================================================== **** mixmaster-3.0/conf/blocked.txt.in0000644000176200017620000000133407406326350017257 0ustar rabbirabbi00000000000000Subject: %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 mixmaster-3.0/conf/usage.txt.in0000644000176200017620000000154407405572320016762 0ustar rabbirabbi00000000000000Subject: 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 mixmaster-3.0/conf/end.hlp0000644000176200017620000000252407406501340015755 0ustar rabbirabbi00000000000000Abuse 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 mixmaster-3.0/conf/mix.cfg0000644000176200017620000000037210277350622015764 0ustar rabbirabbi00000000000000######################## 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 mixmaster-3.0/conf/news.hlp0000644000176200017620000000427207405521034016166 0ustar rabbirabbi00000000000000You 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 [. . .] ================================================================== ***** mixmaster-3.0/conf/header.blk0000644000176200017620000000055307367732047016444 0ustar rabbirabbi00000000000000# 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 mixmaster-3.0/conf/pubring.mix0000644000176200017620000003066410763033773016707 0ustar rabbirabbi00000000000000antani 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----- mixmaster-3.0/conf/mlist.txt0000644000176200017620000000311010763033773016375 0ustar rabbirabbi00000000000000 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% mixmaster-3.0/conf/mix.cfg.ex0000644000176200017620000001314410720247556016404 0ustar rabbirabbi00000000000000## 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 mixmaster-3.0/conf/dest.blk0000644000176200017620000000004407517404143016134 0ustar rabbirabbi00000000000000president@whitehouse.gov majordomo@ mixmaster-3.0/conf/pgp.hlp0000644000176200017620000001217407533372255016013 0ustar rabbirabbi00000000000000You 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 ***** mixmaster-3.0/conf/pgponly.hlp0000644000176200017620000001217507533372255016716 0ustar rabbirabbi00000000000000You 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 ***** mixmaster-3.0/conf/pubring.asc0000644000176200017620000010443410763033773016655 0ustar rabbirabbi00000000000000-----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----- mixmaster-3.0/conf/rab.blk0000644000176200017620000000000007367732047015743 0ustar rabbirabbi00000000000000mixmaster-3.0/conf/rlist.txt0000644000176200017620000001114710763033773016413 0ustar rabbirabbi00000000000000$remailer{"antani"} = " cpunk max mix middle pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; $remailer{"austria"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord klen1024"; $remailer{"beton"} = " cpunk max mix middle pgp repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord klen10000"; $remailer{"borked"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop3 reord post klen1024"; $remailer{"citrus"} = " cpunk max mix middle pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord"; $remailer{"cyberiad"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post"; $remailer{"deuxpi"} = " cpunk max mix middle pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; $remailer{"dizum"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post klen64"; $remailer{"frell"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post klen1024"; $remailer{"george"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post"; $remailer{"hastio"} = " cpunk mix hybrid pgp latent ek ekx esub cut hash repgp remix ext max test inflt75 rhop6 klen1000"; $remailer{"hermetix"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop5 reord post klen5000"; $remailer{"kroken"} = " cpunk mix middle pgp pgponly repgp remix latent hash cut test ek ekx esub inflt50 rhop20 reord klen1024"; $remailer{"metacolo"} = " cpunk mix pgp repgp remix latent hash cut test ek ekx esub inflt50 rhop20 reord post"; $remailer{"nymkey"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; $remailer{"panta"} = " cpunk mix hybrid hcnews pgp latent ek ekx esub cut hash post repgp remix reord ext max test inflt75 rhop5 klen1000"; $remailer{"pboxmix"} = " cpunk max mix pgp pgponly repgp remix latent hash cut test ekx inflt50 rhop5 reord post"; $remailer{"senshi"} = " cpunk middle pgp latent ek ekx esub cut hash repgp reord ext max test inflt10 rhop2 klen200"; $remailer{"starwars"} = " 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% mixmaster-3.0/conf/intro.hlp0000644000176200017620000000111407406330654016344 0ustar rabbirabbi00000000000000Subject: 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. mixmaster-3.0/conf/reply.txt.in0000644000176200017620000000204407405572320017005 0ustar rabbirabbi00000000000000This 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 mixmaster-3.0/Install0000755000176200017620000006723710763040243015125 0ustar rabbirabbi00000000000000#!/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 <tmptst.c #include 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 <tmptst.c int main() { #include 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 <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." mixmaster-3.0/Src/0000755000176200017620000000000010763041472014306 5ustar rabbirabbi00000000000000mixmaster-3.0/Src/stats.c0000644000176200017620000002713510447240327015617 0ustar rabbirabbi00000000000000/* 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 #include #include /* 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 " * 0x759ED311 "znar " * * 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"); } mixmaster-3.0/Src/mixlib.def0000644000176200017620000001137610044577714016267 0ustar rabbirabbi00000000000000LIBRARY 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 mixmaster-3.0/Src/keymgt.c0000644000176200017620000002460010447240327015753 0ustar rabbirabbi00000000000000/* 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 #include #include 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); } mixmaster-3.0/Src/remailer.c0000644000176200017620000000151310447240327016251 0ustar rabbirabbi00000000000000/* 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 /** 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); } mixmaster-3.0/Src/service.c0000644000176200017620000002264110447240327016116 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #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 */ mixmaster-3.0/Src/Makefile.in0000644000176200017620000000447010447240327016357 0ustar rabbirabbi00000000000000# 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 mixmaster-3.0/Src/mix.h0000644000176200017620000006120410447240327015256 0ustar rabbirabbi00000000000000/* 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 #include #ifdef WIN32 #include #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 */ mixmaster-3.0/Src/nym.c0000644000176200017620000003641310447240327015263 0ustar rabbirabbi00000000000000/* 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 #include #include 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 */ mixmaster-3.0/Src/mpgp.c0000644000176200017620000001412510447240327015417 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #include #include #include #ifdef POSIX #include #include #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); } mixmaster-3.0/Src/chain1.c0000644000176200017620000002054710447240327015624 0ustar rabbirabbi00000000000000/* 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 #include #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 */ mixmaster-3.0/Src/chain2.c0000644000176200017620000004756210447240327015633 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #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, "")) 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); } mixmaster-3.0/Src/pgpcreat.c0000644000176200017620000004704310447240327016266 0ustar rabbirabbi00000000000000/* 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 #include #include 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 */ mixmaster-3.0/Src/rfc822.c0000644000176200017620000003227110447240327015464 0ustar rabbirabbi00000000000000/* 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 = , ; => may be folded * "\" & CR, and including * linear-white-space> */ static int is_qtext(char c) { return (c != '\"' && c != '\\' && c != '\n'); } /* ctext = 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* */ 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* */ 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); } mixmaster-3.0/Src/config.h0000644000176200017620000002570610763026612015735 0ustar rabbirabbi00000000000000/* 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 mixmaster-3.0/Src/util.c0000644000176200017620000003637710447240327015446 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #include #ifdef POSIX #include #include #include #include #include #else /* end of POSIX */ #include #endif /* else if not POSIX */ #ifdef HAVE_GETKEY #include #endif /* HAVE_GETKEY */ #include /** 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 */ mixmaster-3.0/Src/pgpdata.c0000644000176200017620000010770510447240327016103 0ustar rabbirabbi00000000000000/* 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 #include #include 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 */ mixmaster-3.0/Src/tests/0000755000176200017620000000000010763041472015450 5ustar rabbirabbi00000000000000mixmaster-3.0/Src/tests/test-parse_yearmonthday.c0000644000176200017620000000216207717747222022503 0ustar rabbirabbi00000000000000#include #include #include #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); } } mixmaster-3.0/Src/compress.c0000644000176200017620000001126610447240327016312 0ustar rabbirabbi00000000000000/* 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 #include 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); } mixmaster-3.0/Src/buffers.c0000644000176200017620000003565710447240327016125 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #ifdef WIN32 #include #endif /* WIN32 */ #include #ifdef POSIX #include #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 */ mixmaster-3.0/Src/parsedate.y0000644000176200017620000005654607746604165016503 0ustar rabbirabbi00000000000000%{ /* $Id: parsedate.y 647 2003-10-25 23:34:13Z weasel $ ** ** Originally written by Steven M. Bellovin while ** at the University of North Carolina at Chapel Hill. Later tweaked by ** a couple of people on Usenet. Completely overhauled by Rich $alz ** and Jim Berets in August, 1990. ** Further revised (removed obsolete constructs and cleaned up timezone ** names) in August, 1991, by Rich. Paul Eggert ** helped in September, 1992. ** ** This grammar has six shift/reduce conflicts. ** ** This code is in the public domain and has no copyright. */ #include #include // #include "config.h" // #include "clibrary.h" #include #if defined(_HPUX_SOURCE) # include #endif #ifdef TM_IN_SYS_TIME # include #else # include #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 are only vaild on ASCII characters (those characters that isascii() says are ASCII). This comes into play when applying 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 tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT %type tSNUMBER tUNUMBER tZONE numzone zone %type 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) */ mixmaster-3.0/Src/menuutil.c0000644000176200017620000000602010447240327016311 0ustar rabbirabbi00000000000000/* 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 #include #include #include 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); } mixmaster-3.0/Src/menu.c0000644000176200017620000005335410447240327015427 0ustar rabbirabbi00000000000000/* 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 #include #include #include #ifdef POSIX #include #else /* end of POSIX */ #include #endif /* else if not POSIX */ #include 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 */ mixmaster-3.0/Src/rem1.c0000644000176200017620000003604510447240327015325 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include 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); } mixmaster-3.0/Src/rem2.c0000644000176200017620000002476710447240327015336 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #ifdef POSIX #include #else /* end of POSIX */ #include #endif /* else if not POSIX */ #ifndef _MSC #include #endif /* not _MSC */ #include 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); } mixmaster-3.0/Src/menu.h0000644000176200017620000000241010447240327015417 0ustar rabbirabbi00000000000000/* 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 #else /* end of HAVE_NCURSES_H */ #include #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 */ mixmaster-3.0/Src/pool.c0000644000176200017620000005350210447240327015427 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #ifdef POSIX #include #else /* end of POSIX */ #include #endif /* else if not POSIX */ #ifndef _MSC #include #endif /* not _MSC */ #include #include #include #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); } mixmaster-3.0/Src/menusend.c0000644000176200017620000003123510447240327016273 0ustar rabbirabbi00000000000000/* 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 #include #include #ifdef POSIX #include #else /* end of POSIX */ #include #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); } mixmaster-3.0/Src/crypto.c0000644000176200017620000002465010447240327016000 0ustar rabbirabbi00000000000000/* 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 #include #include #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 */ mixmaster-3.0/Src/dllmain.c0000644000176200017620000000157110447240327016075 0ustar rabbirabbi00000000000000/* 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 */ mixmaster-3.0/Src/random.c0000644000176200017620000000765110447240327015742 0ustar rabbirabbi00000000000000/* 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 #ifdef POSIX #include #include #else /* end of POSIX */ #include #include #endif /* else if not POSIX */ #ifdef WIN32 #include #endif /* WIN32 */ #include #include 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 */ mixmaster-3.0/Src/maildir.c0000644000176200017620000002006210447240327016072 0ustar rabbirabbi00000000000000/* 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 #include #include #define S_IWUSR _S_IWRITE #define S_IRUSR _S_IREAD #else /* end of WIN32 */ #include #endif /* else not WIN32 */ #include #include #include #include #include #include #include #include #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 /* 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 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 */ mixmaster-3.0/Src/chain.c0000644000176200017620000002704110447240327015537 0ustar rabbirabbi00000000000000/* 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 #include #include #include 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; } mixmaster-3.0/Src/mail.c0000644000176200017620000005062010447240327015376 0ustar rabbirabbi00000000000000/* 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 #include #include #if defined(UNIX) && defined(USE_SOCK) #include #include #include #include #include #include #endif /* defined(UNIX) && defined(USE_SOCK) */ #include #include #include #include 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 */ mixmaster-3.0/Src/menustats.c0000644000176200017620000002274010447240327016501 0ustar rabbirabbi00000000000000/* 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 #include #include #include "menu.h" #ifdef WIN32 #include #pragma comment(lib,"urlmon.lib") #else #include #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; idata); 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; ilength > 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= 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 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 mixmaster-3.0/Src/rem.c0000644000176200017620000004471410447240327015246 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #include #ifdef POSIX #include #else /* end of POSIX */ #include #endif /* else if not POSIX */ #ifndef _MSC #include #endif /* not _MSC */ #include 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); } mixmaster-3.0/Src/main.c0000644000176200017620000005423110447257664015416 0ustar rabbirabbi00000000000000/* 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 #include #include #include #ifdef POSIX #include #else /* end of POSIX */ #include #endif /* else if not POSIX */ #include 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; } mixmaster-3.0/Src/rndseed.c0000644000176200017620000000663110447240327016103 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #ifdef POSIX #include #include #else /* end of POSIX */ #include #include #endif /* else if not POSIX */ #if defined(WIN32) || defined(MSDOS) #include #endif /* defined(WIN32) || defined(MSDOS) */ #ifdef WIN32 #include #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); } mixmaster-3.0/Src/mix3.h0000644000176200017620000003172710447240327015350 0ustar rabbirabbi00000000000000/* 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 #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 /* 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 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 */ mixmaster-3.0/Src/crypto.h0000644000176200017620000000242510447240327016001 0ustar rabbirabbi00000000000000/* 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 #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 #include #include #include #include #include #include #include #include #ifdef USE_IDEA #include #endif /* USE_IDEA */ #ifdef USE_AES #include #endif /* USE_AES */ #include #include 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 */ mixmaster-3.0/Src/pgp.c0000644000176200017620000002724110447240327015245 0ustar rabbirabbi00000000000000/* 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 #include 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 */ mixmaster-3.0/Src/Makefile.deps0000644000176200017620000000362610447240327016706 0ustar rabbirabbi00000000000000# 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 mixmaster-3.0/Src/pgpget.c0000644000176200017620000004434310447240327015747 0ustar rabbirabbi00000000000000/* 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 #include #include 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 */ mixmaster-3.0/Src/mime.c0000644000176200017620000004643710447240327015416 0ustar rabbirabbi00000000000000/* 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 #include #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 */ } mixmaster-3.0/Src/menunym.c0000644000176200017620000002643010447240327016146 0ustar rabbirabbi00000000000000/* 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 #include #ifdef POSIX #include #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 */ mixmaster-3.0/Src/version.h0000644000176200017620000000002610763033773016147 0ustar rabbirabbi00000000000000#define VERSION "3.0" mixmaster-3.0/Src/pgp.h0000644000176200017620000001364010447240327015250 0ustar rabbirabbi00000000000000/* 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 #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 */ mixmaster-3.0/Src/dummy.c0000644000176200017620000000033310066112621015573 0ustar rabbirabbi00000000000000/* 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; } mixmaster-3.0/Src/pgpdb.c0000644000176200017620000003603310447240327015552 0ustar rabbirabbi00000000000000/* 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 #include #include #include 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 */ mixmaster-3.0/Src/mix.c0000644000176200017620000010213610720311321015234 0ustar rabbirabbi00000000000000/* 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 #include #include #include #include #include #include #include #ifdef POSIX #include #include #include #include #else /* end of POSIX */ #include #include #endif /* else if not POSIX */ #ifdef WIN32 #include #include #include #endif /* WIN32 */ #include #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 ~/) * - 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); } mixmaster-3.0/COPYRIGHT0000644000176200017620000001407610745134070015057 0ustar rabbirabbi00000000000000Copyright (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. mixmaster-3.0/THANKS0000644000176200017620000000536210763033773014505 0ustar rabbirabbi00000000000000Mixmaster 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 mixmaster-3.0/mixmaster.10000644000176200017620000006543210763033773015671 0ustar rabbirabbi00000000000000.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. mixmaster-3.0/README0000644000176200017620000002034110763033773014444 0ustar rabbirabbi00000000000000Mixmaster 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 $