--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+Installing SILC Developer's Version
+===================================
+
+./configure
+./make
+
+You should not install the SILC into your system, instead, you should
+run it from the current directory.
+
+To see different compilation options, give,
+
+./configure --help
+
+
+Generally, developers wants to compile with debugging, in this case,
+give,
+
+./configure --enable-debug
+
+WARNING: The debugging is very very heavy and you currently cannot turn
+it off if you have compiled it with this option. However, if you're
+going to develop or debug SILC you whould compile with this option.
+
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+SUBDIRS = lib silcd silc doc includes
--- /dev/null
+SILC - Secure Internet Live Conferencing
+========================================
+
+[NOTE: SILC is still in middle of development and this package is known
+as Developer's Version which means that the package is in no means stable
+or ready to be in production use. This package is for those who wants
+to test SILC, find bugs and maybe contribute some time and code for the
+SILC project. There is no guarantees that this package even compiles and
+even if it compiles there is no guarantees that it would work, and even
+if it works there is no guarantees that it would work correctly, and even
+if it seems to work correctly it may be just plain luck.]
+
+
+Description
+===========
+
+SILC (Secure Internet Live Conferencing) is a protocol which provides
+secure conferencing services in the Internet over insecure channel.
+SILC is IRC like softwarre although internally they are very different.
+Biggest similiarity between SILC and IRC is that they both provide
+conferencing services and that SILC has almost same commands as IRC. Other
+than that they are nothing alike. Biggest differences are that SILC is
+secure what IRC is not in any way. The network model is also entirely
+different compared to IRC.
+
+
+Features
+========
+
+Features to be included into the final release of SILC. [Note that the
+current Developer's Version does not include all of these features, read
+TODO file for more information.]
+
+ o Normal conferencing services such as private messages, channels,
+ channel messages, etc. All traffic is secured and authenticated.
+
+ o No unique nicknames. There can same nicknames in SILC without
+ collisions. SILC has unique Client ID's, Server ID's and Channel ID's
+ to assure that there are no collisions.
+
+ o Secure key exchange and authentication protocol. SILC Key Exchange
+ protocol provides key material used in the SILC sessions in secure
+ manner. The protocol is immune for example to man-in-the-middle
+ attacks. The SILC Authentication protocol provides strong
+ authentication. Authentication may be based on passphrase or public
+ key (RSA) authentication. For clients there is an option not to
+ use authentication when connecting to servers.
+
+ o All traffic is encrypted and authenticated using the best cryptographic
+ algorithms out there. Command messages, private messages and channel
+ messages are all protected by encryption. User can set private keys
+ for both private message and for channels so that even SILC servers do
+ not know the keys. Cipher keys are, by default, 128 bits in length and
+ public keys, by default, 1024 bits in length.
+
+ o Supports data compression with GZIP to improve performance.
+
+ o SIM (SILC Module) support. Support for loading of shared objects at
+ run-time that provides new and extended features to both SILC client
+ and server. These can provide extra ciphers and extra features to
+ the software.
+
+ o SILC client can be installed and used without root privileges.
+
+ o SILC client can be configured by system wide configuration files but
+ with user specific configuration files as well.
+
+
+History
+=======
+
+Even though SILC were just released to the public the idea and the protocol
+itself is quite old. I got the idea about SILC in its current form in
+the year 1996 and first lines of codes were written in early 1997. This
+release is now third rewrite of the SILC. The very first version were
+written in 1997 and it included SILC client and very very preliminary
+SILC server. The server actually weren't usable but the client looked
+pretty much the same as it does now. At that time the SILC also included
+RSA implementation and 3DES implementation. The random number generator
+that exists in this current release is actually based on the RNG written
+in 1997. The RNG written in 1997, on the other hand, were based on
+the SSH's random number generator. The RNG has been rewritten twice
+since the first version.
+
+I stopped writing the SILC later in 1997 when I got busy at school and
+in work. The pause lasted several months. The development resumed in
+1998 when my friend (Juha Räsänen) and I implemented ElGamal algorithm.
+I rewrote some other parts as well. However, for the same reasons as
+previously the development stopped again. I resumed the development
+later in 1998 by doing rewrite of the SILC in C++. This was obviously
+a mistake but at that time it seemed like a good idea. Again, in the
+winter 1999 I got very busy writing my thesis and was forced to stop the
+development again. I also, started a new job in the spring.
+
+Later, in 1999, I decided that this time I'm going to make it the right
+way. C++ was obviously a bad choice so I decided to fall back to plain
+C language. I also decided to do complete rewrite and started doing
+more thorough planning of what the SILC actually should include. I also
+decided that this time it is going to kill me before I stop the
+development. I started writing SILC in the weekends and actually
+everytime I had some spare time. I also started a new job but I didn't
+let that get to my way. The result of this development effort is the
+release now in public.
+
+I've learned a lot by doing the SILC. I guess, when I started it I wasn't
+that good of a C programmer. That alone was a reason why SILC hasn't
+seen the day of light before now. My programming style has also changed
+dramatically during these years. Actually, it has changed couple times
+since this last rewrite as well. However, the code style of current SILC
+release is quite consistent (actually the coding style SILC has been
+written now I've learned in my current job).
+
+There is probably over 85% of new code in this third rewrite. Rest has
+just been copied from the old versions and only minor changes has been
+made (like changed function names and overall coding style). I've
+preserved the dates of the old files (dating back to 1997) that has
+existed in some forms in the old versions. There is a lot of new code but
+already I see a lot that needs rewriting. The development continues.
+
+
+Contact
+=======
+
+Feedback and comments are welcome. You can reach me in the following
+Address.
+
+[Note that generally bug reports should not be sent just yet as the
+Developer's Version is full of them and the bug hunt has not even started
+yet.]
+
+ Pekka Riikonen <priikone@poseidon.pspt.fi>
--- /dev/null
+TODO
+====
+
+This is more or less complete list of tasks that has to be done before
+SILC 1.0 could ever be released. It is clear that the list does not
+include all the bugs that exists. At the end of list are tasks that
+needs to be done but are probably post 1.0.
+
+Feel free to contribute if you have the ability and free time - all the
+help is really appreciated - and needed.
+
+ - Pekka
+
+[Latest Note: The protocol has changed a bit in some parts which
+causes that the current implementation violates some requirements.
+These are not listed here, currently.]
+
+
+New features TODO
+=================
+
+ o Extended SIM (SILC Module) support. Currently only SILC Cipher API
+ and SILC Hash API may be used as SIM's. What I have in mind is to
+ have extended support for SIM's so that basically any SILC API could
+ be used as SIM's. This would open tremendous possiblities but
+ opens also issues on security that needs to be dealt with.
+
+ Some sort of SIM compilation environment should be defined so that
+ the SIM's could use SILC specific symbols from the modules (which they
+ cannot do currently). In the future modules could add new features
+ to SILC easily with this support. I'm more thinking this from client's
+ perspective to add new features to client (such as IRC support as SIM)
+ but server should have the support as well. Anyhow, this is an
+ interesting feature...
+
+ This maybe post 1.0 task - dunno.
+
+ o SIM support for other platforms than just for Linux. Apache has
+ example code (code that we could use directly pretty easily) for
+ other platforms.
+
+ o We should replace all short, int, long, unsigned short, unsigned int,
+ unsigned long with some pre-defined datatypes that really are what
+ we want on all platforms. int16, uint16, int32, uint32 etc. are
+ what we could use or maybe SilcInt16, SilcUInt16 etc. Also, boolean
+ datatype should be defined.
+
+ o More platform supports should be added. The code is pretty much
+ generic but there are some parts that require porting (SIM). Also,
+ some support for different platforms is needed into configure.in.
+
+ o SILC requires currently GCC to work because we use GCC specific
+ compilation options. Generally any compiler that supports inline
+ functions and can build shared libraries (for SIMs) should work.
+ These cases should be included into configure.in.
+
+
+TODO In SILC Client
+===================
+
+ o Implement all commands. A lot of commands are still yet to be
+ implemented. Most of them are trivial but some will require some
+ planning. Go see the command.c for unimplemented commands.
+
+ o Non-blocking connection on the background must be stopped if some
+ other connection on same window has established. Now it is possible
+ that some non-blocking connection timeouts on the background when
+ we already have a working connection to some other place; things
+ goes bad.
+
+ o Finish WHOIS, finish JOIN and other commands that are partly
+ implemented.
+
+ o Input line on UI is buggy. Cursor movement etc bugs. Too lazy to
+ fix it.
+
+ o Logic for handling multiple same nicknames for example in private
+ message sending. I guess the logic is done in server side but is
+ missing from client.
+
+ o Private message key setting is missing and must be implemented.
+ Currently private messages are encrypted with session keys. This
+ is required by the protocol.
+
+ o Channel private key setting is missing and must be implemented.
+ Currently there cannot be private keys for channels. Normal channel
+ keys (generated by server) are used. This is required by the protocol.
+
+ o Public and private key generation is now done everytime the program
+ is run. Now, this is only for testing period as I've been lazy to
+ do it any better for now. This must be fixed.
+
+ o I guess, public key authentication (when connecting to a server)
+ is not working currently. It is just matter of loading the keys
+ from file and using them (see corresponding code in server, it should
+ support public key authentication already).
+
+ o Multiple windows support. Basic support for multiple windows already
+ exists but a lot is still missing to get it working. Also, some
+ of the existing stuff probably needs to be tweaked a bit before the
+ multiple windows support could be done. And of course the actual
+ commands that control the windows needs to be written (/WINDDOW).
+
+ o Implement /KEYMAP (or similiar) command to remap control and function
+ keys.
+
+ o Implement /ALIAS command to make command aliases.
+
+ o Implement /set/if/do/while etc as in IRC2. Maybe post 1.0 task.
+ Some scripting would be good.
+
+ o Connection Authentication request resolving is missing and must be
+ done. This is required by the protocol.
+
+ o Key Exchange protocol's responder side is missing from client.
+ Generally it is possible for the client to be responder so it should
+ be implemented (See corresponding code from server). Error handling
+ in the KE protocol is also in pretty bad shape in client.
+
+ o Configuration file loading from global and from local dirs. This
+ is currently missing and I guess the global is only used. Old SILC
+ version (in 1997) had ~./silc directory that I guess should be done
+ now as well. The code for handling those exists but not in current
+ source tree.
+
+ o Configuration file format - could be better.
+
+ o Write help files for commands. Nice format for the help files should
+ be selected. I'm open for ideas.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+ Also, return values from various allocations and functions needs to
+ checked.
+
+
+TODO In SILC Server
+===================
+
+ o Implement all commands on server side. A lot of commands are still yet
+ to be implemented. Most of them are trivial but some will require some
+ planning. Go see the command.c for unimplemented commands.
+
+ o DNS/IP lookup blocks the server. This must be fixed. Check the
+ resolver stuff (resolver(3), resolver(5)). Either we have to do the
+ own resolver stuff (through scheduler, if possible without writing
+ too much own stuff) or use threads.
+
+ o Lenght of the packet processing timeouts needs to be checked whether
+ they are too short or too long. I haven't really tested whether they
+ are suitable. They should be tested on high load which I haven't done
+ at all yet.
+
+ o Public and private key generation is now done everytime the program
+ is run. Now, this is only for testing period as I've been lazy to
+ do it any better for now. This must be fixed.
+
+ o Server says that it is able to listen on multiple ports but currently
+ that is bogus. It can, but internals are for single server.
+
+ o Command lagging must implemented. Those commands (all currently) that
+ has the LAG flag set they must not be allowed to be executed more than
+ once, say, in 2 seconds.
+
+ o Command flag usage in general is not implemented yet.
+
+ o Client history must be implemented. Protocol says that server must
+ keep history information about clients for some period of time.
+
+ o Channel flags and user modes on channels are not implemented yet as
+ /MODE command is not implemented yet in client and server.
+
+ o Protocol execution timeouts are hard coded, should be configurable.
+
+ o Channel message sending routines uses a lot of common code. Should
+ create a common function for those instead of writing the same code
+ again everytime, as done now.
+
+ o serverutil.c I guess should be created for util-like functions that
+ now resides in server.c, which is getting too big.
+
+ o serverconfig.c and the function naming in it is inconsistent. It is
+ not silc_config_server* it should be silc_server_config*. As should
+ all the SilcConfigServer* types be SilcServerConfig*.
+
+ o Implement DENY_CONNECTION section in serverconfig.c and in server.
+
+ o Implement REDIRECT_CLIENT section in serverconfig.c and in server.
+
+ o Configuration file format - could be better.
+
+ o IP address fields in configuration file should accept mask format
+ as well, IP/MASK, and not just plain IP.
+
+ o Connection classes should be actually implemented in serverconfig.c.
+ They can be defined but they are totally ignored currently.
+
+ o Acceptance of incoming connections (client and server connections)
+ should be checked before key exchange protocol. Currently it is
+ checked at the authentication phase after KE, that is ok, but it should
+ be checked before starting KE, as well.
+
+ o Statistics are totally missing from the server. It would be nice
+ to gather some statistics.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+ Also, return values from various allocations and functions needs to
+ checked.
+
+
+TODO In SILC Libraries
+======================
+
+ o Public key verification in SKE (SILC Key Exchange) protocol is missing,
+ thus currently we trust on all public keys. This probably doesn't cause
+ bad problems but the mechanism of verifying it from local database
+ (from files) needs to be done (it can open man-in-the-middle-attacks).
+
+ o Implement PFS (Perfect Forward Secrecy) flag in SKE (and in client and
+ server, actually). If PFS is set, re-key must cause new key exchange.
+ This is required by the SILC protocol.
+
+ o Re-key in general is actually missing (from everywhere) and must be done.
+
+ o SKE does not send correct status types. Types are defined but not
+ sent.
+
+ o Connection authentication protocol does not send correct status types.
+ These types are not defined currently at all.
+
+ o PKCS#1 style RSA public key encryption/decryption/sign/verify is
+ missing, and should be added for interoperability reasons. The thing
+ I've done now is bad and should be removed as soon as possible (or
+ the protocol should then state the method of how they should be done).
+
+ o SILC public key file type is bad. I'd like to see PEM encoded files.
+ I have public domain code for base64 encoding but it needs to be
+ rewritten.
+
+ o Slow ciphers should be removed. I think we don't need more than
+ the AES finalists plus blowfish and RC5.
+
+ o These slow ciphers actually don't work currently as I've tested
+ only the ones that are worth testing. The CBC mode on these slow
+ ciphers probably don't work. No need to worry, these ciphers should
+ be removed.
+
+ o Scheduler needs to be analyzed on high load as it might be unfair
+ towards select() because it may run timeout tasks before select() and
+ after select(). If it is found to be unfair the timeout task running
+ before select() should probably be removed.
+
+ o On select() issue; maybe we should use poll() instead if it is
+ available? poll() doesn't have max fd limit...
+
+ o SIM support for SILC PKCS API needs to made so that they could be
+ used as SIM's. At the same time some work is required on prime
+ generation as the way it is done now sucks. Read from code for
+ more (silcpkcs.h).
+
+ o Compression routines are missing. The protocol supports packet
+ compression thus it must be implemented. SILC Comp API must be
+ defined. zlib package is already included into the lib dir (in CVS,
+ not in distribution), but it is not used yet, and it requires some
+ tweaking on the Makefiles (we want static lib not shared).
+
+ o Cipher API needs to be made more consistent. Some parts of the
+ code generated with current Cipher API looks really bad. Same
+ is with PKCS API, even worse actually. They need to be made
+ cleaner. Introducing silc_cipher_encrypt/decrypt/set_key etc.
+ functions (I actually don't understand why have I left these un-done).
+
+ o Scheduler should automatically allocate task queues if NULL pointers
+ are passed to the silc_schedule_init. Would make initialization
+ cleaner.
+
+ o Packet processing routines in client and server are actually pretty
+ much generic and should be moved from the client/server to the library
+ as generic routines (silc_<client/server>_packet_decrypt_rest* etc).
+ This requires heavy changes to the client and server.
+
+ o Random Number Generator needs some tweaking. Reading /dev/random may
+ block resulting slow initialization of RNG. Some other things in the
+ RNG may block as well. Also, I have some pending changes to the RNG
+ that needs to be commited (from Schneier's Yarrow-160 paper). They
+ should make the RNG even better.
+
+ o Logging should be made more generic in a way that application can
+ set to where the logging is destined to. Now, it is always destined
+ to stdout (or stderr) which is a bad thing for client. Ie. some
+ sort of logging registration functions or similiar should be done
+ (silclog.[ch] in core). The actual output of logs should be done
+ by callback function in the application not in lib.
+
+ o I don't like the ID cache system currenly implemented. Ugly and
+ not so good. Must be rewritten very soon.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+
+ o There are also checks missing from allocations whether the allocation
+ returns valid memory or NULL. These are missing in library as well
+ in client and server. Either all checks has to be added or we will
+ have to make sure that silc_*alloc()s always return valid memory
+ and assert()s if the system's memory allocator (*alloc()) fails.
+
+ o silc_buffer_[un]format() needs to be made more stable as it may
+ crash the SILC if malformed data is sent as argument. There are a
+ lot of places in client and server where we trust directly data coming
+ from network and try to unformat it. The unformatting routine needs
+ to be able handle situations where data sent is malformed, by mistake
+ or intentionally. This is important as it is easy to crash the SILC
+ now by just sending malformed data. Also, in client and server we
+ must start checking the return value from silc_buffer_[un]format.
+
+
+Other Things TODO
+=================
+
+ o Write manuals for server.
+
+ o Write manuals for client.
+
+ o Write SILC Library Reference manual. This would include all the SILC
+ API's with simple examples how the functions are to be used. This is
+ pretty easy to create by taking all the functions plus their comments
+ from source/header files. However, same sort of reference manual
+ should be written for client and server as well.
+
+
+TODO After 1.0
+==============
+
+ o Pthreads support. A lot of problems are solved with server (and with
+ client as well) if we add pthread support. We can forget things such
+ as non-blocking connecting etc, and we can do things such as DNS/IP
+ lookups async. The server itself also benefits great deal from
+ threads, especially from performance point of view.
+
+ But, this is not a small task and almost entire SILC Library has to
+ be made re-entrant. Own API is probably added for the threads support
+ to make changes in the future as painless as possible. So the API
+ would have things like silc_mutex_lock, silc_mutex_unlock and
+ friends...
+
+ o X.509 certificate support. SILC protocol supports certificates and
+ it would be great to have support for them. This is a big task as
+ support has to be made for ASN.1 as well. I've looked into OpenSSL
+ package as it has X.509 certificate support (and ASN.1 as well).
+ The code does not look very good to my eye but it has some potentials.
+ This should be looked at more closely.
+
+ Naturally own SILC Certificate API has to be defined regardles what
+ the actual X.509 library is (OpenSSL X.509 or something else). Other
+ choice is to write own X.509 library but I'm not going to do it -
+ I can help to migrate the OpenSSL X.509 into SILC and I can help if
+ someone would like to write the X.509 library - but I'm not going
+ to start writing one myself. Anyhow, the OpenSSL X.509 lib should
+ be checked.
+
+ o SSH2 public keys support. Maybe - not really needed but could be
+ nice as SSH is widely used all over the place. SILC Protocol
+ supports SSH2 public keys.
+
+ o IRC support for SILC client. This would be nice to have on client
+ as it could be used to connect to SILC and IRC. People wouldn't
+ have to have two different clients when same would work on both.
+ I'd like to see this done as SIM, after the extended SIM support
+ has been added to SILC.
+
+ o Cipher optimizations (asm, that this) at least for i386 would be nice.
--- /dev/null
+/* Name of the package. */
+#undef PACKAGE
+
+/* Version of the package. */
+#undef VERSION
+
+/* Debugging */
+#undef SILC_DEBUG
+
+/* Default configuration file */
+#undef SILC_SERVER_CONFIG_FILE
+
+/* SIM (SILC Module) support */
+#undef SILC_SIM
+#undef HAVE_RTLD_NOW
+#undef HAVE_RTLD_LAZY
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS = silc
+
+silc_SOURCES = \
+ silc.c \
+ client.c \
+ command.c \
+ command_reply.c \
+ clientconfig.c \
+ clientutil.c \
+ protocol.c \
+ screen.c
+
+LDADD = -L. -L.. -L../lib -lsilc -lcurses
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
+ -I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
+ -I../includes \
+ -I../lib/silcmath/gmp-3.0.1
--- /dev/null
+/*
+
+ client.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Static function prototypes */
+static int silc_client_bad_keys(unsigned char key);
+static void silc_client_process_message(SilcClient client);
+static char *silc_client_parse_command(unsigned char *buffer);
+
+/* Static task callback prototypes */
+SILC_TASK_CALLBACK(silc_client_update_clock);
+SILC_TASK_CALLBACK(silc_client_run_commands);
+SILC_TASK_CALLBACK(silc_client_process_key_press);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
+SILC_TASK_CALLBACK(silc_client_packet_process);
+SILC_TASK_CALLBACK(silc_client_packet_parse);
+
+SilcClientWindow silc_client_create_main_window(SilcClient client);
+SilcClientWindow silc_client_add_window(SilcClient client,
+ int is_current);
+void silc_client_packet_parse_type(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_private_message_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+
+/* Definitions from version.h */
+extern char *silc_version;
+extern char *silc_name;
+extern char *silc_fullname;
+
+/* Allocates new client object. This has to be done before client may
+ work. After calling this one must call silc_client_init to initialize
+ the client. */
+
+int silc_client_alloc(SilcClient *new_client)
+{
+
+ *new_client = silc_calloc(1, sizeof(**new_client));
+ if (*new_client == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new client object"));
+ return FALSE;
+ }
+
+ (*new_client)->input_buffer = NULL;
+ (*new_client)->screen = NULL;
+ (*new_client)->windows = NULL;
+ (*new_client)->windows_count = 0;
+ (*new_client)->current_win = NULL;
+
+ return TRUE;
+}
+
+/* Free's client object */
+
+void silc_client_free(SilcClient client)
+{
+ if (client) {
+ silc_free(client);
+ }
+}
+
+/* Initializes the client. This makes all the necessary steps to make
+ the client ready to be run. One must call silc_client_run to run the
+ client. */
+
+int silc_client_init(SilcClient client)
+{
+
+ SILC_LOG_DEBUG(("Initializing client"));
+ assert(client);
+
+ client->username = silc_get_username();
+ client->realname = silc_get_real_name();
+
+ /* Register all configured ciphers, PKCS and hash functions. */
+ client->config->client = (void *)client;
+ silc_client_config_register_ciphers(client->config);
+ silc_client_config_register_pkcs(client->config);
+ silc_client_config_register_hashfuncs(client->config);
+
+ /* Initialize hash functions for client to use */
+ silc_hash_alloc("md5", &client->md5hash);
+ silc_hash_alloc("sha1", &client->sha1hash);
+
+ /* Initialize none cipher */
+ silc_cipher_alloc("none", &client->none_cipher);
+
+ /* Initialize random number generator */
+ client->rng = silc_rng_alloc();
+ silc_rng_init(client->rng);
+ silc_math_primegen_init(); /* XXX */
+
+#if 0
+ {
+ SilcCipher twofish;
+ unsigned char *src, *dst, *dec;
+ SilcBuffer packet;
+ int payload_len;
+
+ payload_len = 4 + strlen("pekka riikonen");
+ packet = silc_buffer_alloc(payload_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(payload_len),
+ SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
+ SILC_STR_UI_XNSTRING("pekka riikonen",
+ strlen("pekka riikonen")),
+ SILC_STR_END);
+
+ silc_cipher_alloc("twofish", &twofish);
+ twofish->cipher->set_key(twofish->context, "1234567890123456", 16);
+ twofish->set_iv(twofish, "6543210987654321");
+ SILC_LOG_HEXDUMP(("source: len %d", packet->len),
+ packet->data, packet->len );
+ silc_packet_encrypt(twofish, packet, packet->len);
+ SILC_LOG_HEXDUMP(("encrypted"), packet->data, packet->len);
+ silc_packet_decrypt(twofish, packet, packet->len);
+ SILC_LOG_HEXDUMP(("decrypted"), packet->data, packet->len);
+
+ }
+
+ {
+ SilcCipher cipher1, cipher2;
+ unsigned char *src, *dst, *dec;
+ int len = strlen("12345678901234561234567890123456123456789012345612345678901234561234567890123456");
+
+ src = silc_calloc(len + 1, sizeof(unsigned char));
+ dst = silc_calloc(len + 1, sizeof(unsigned char));
+ dec = silc_calloc(len + 1, sizeof(unsigned char));
+
+ memcpy(src, "12345678901234561234567890123456123456789012345612345678901234561234567890123456", len);
+
+ silc_cipher_alloc("twofish", &cipher1);
+ cipher1->cipher->set_key(cipher1->context, "1234567890123456", 128);
+ cipher1->set_iv(cipher1, "6543210987654321");
+
+ silc_cipher_alloc("twofish", &cipher2);
+ cipher2->cipher->set_key(cipher2->context, "1234567890123456", 128);
+ cipher2->set_iv(cipher2, "6543210987654321");
+
+ SILC_LOG_HEXDUMP(("source: %d", len), src, len);
+ cipher1->cipher->encrypt(cipher1->context, src, src, len, cipher1->iv);
+ SILC_LOG_HEXDUMP(("encrypted"), src, len);
+ cipher2->set_iv(cipher2, "6543210987654321");
+ cipher2->cipher->decrypt(cipher2->context, src, src, len, cipher2->iv);
+ SILC_LOG_HEXDUMP(("decrypted"), src, len);
+
+ }
+#endif
+
+ /* Register the task queues. In SILC we have by default three task queues.
+ One task queue for non-timeout tasks which perform different kind of
+ I/O on file descriptors, timeout task queue for timeout tasks, and,
+ generic non-timeout task queue whose tasks apply to all connections. */
+ silc_task_queue_alloc(&client->io_queue, TRUE);
+ if (!client->io_queue) {
+ goto err0;
+ }
+ silc_task_queue_alloc(&client->timeout_queue, TRUE);
+ if (!client->timeout_queue) {
+ goto err1;
+ }
+ silc_task_queue_alloc(&client->generic_queue, TRUE);
+ if (!client->generic_queue) {
+ goto err1;
+ }
+
+ /* Initialize the scheduler */
+ silc_schedule_init(client->io_queue, client->timeout_queue,
+ client->generic_queue, 5000);
+
+ /* Register the main task that is used in client. This received
+ the key pressings. */
+ if (silc_task_register(client->io_queue, fileno(stdin),
+ silc_client_process_key_press,
+ (void *)client, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL) == NULL) {
+ goto err2;
+ }
+
+ /* Register timeout task that updates clock every minute. */
+ if (silc_task_register(client->timeout_queue, 0,
+ silc_client_update_clock,
+ (void *)client,
+ silc_client_time_til_next_min(), 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW) == NULL) {
+ goto err2;
+ }
+
+ if (client->config->commands) {
+ /* Run user configured commands with timeout */
+ if (silc_task_register(client->timeout_queue, 0,
+ silc_client_run_commands,
+ (void *)client, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW) == NULL) {
+ goto err2;
+ }
+ }
+
+ /* Allocate the input buffer used to save typed characters */
+ client->input_buffer = silc_buffer_alloc(SILC_SCREEN_INPUT_WIN_SIZE);
+ silc_buffer_pull_tail(client->input_buffer,
+ SILC_BUFFER_END(client->input_buffer));
+
+ /* Initialize the screen */
+ client->screen = silc_screen_init();
+ silc_client_create_main_window(client);
+ client->screen->input_buffer = client->input_buffer->data;
+ silc_screen_print_coordinates(client->screen, 0);
+
+ return TRUE;
+
+ err0:
+ silc_task_queue_free(client->timeout_queue);
+ err1:
+ silc_task_queue_free(client->io_queue);
+ err2:
+ return FALSE;
+}
+
+/* Stops the client. This is called to stop the client and thus to stop
+ the program. */
+
+void silc_client_stop(SilcClient client)
+{
+ SILC_LOG_DEBUG(("Stopping client"));
+
+ /* Stop the scheduler, although it might be already stopped. This
+ doesn't hurt anyone. This removes all the tasks and task queues,
+ as well. */
+ silc_schedule_stop();
+ silc_schedule_uninit();
+
+ SILC_LOG_DEBUG(("Client client"));
+}
+
+/* Runs the client. */
+
+void silc_client_run(SilcClient client)
+{
+ SILC_LOG_DEBUG(("Running client"));
+
+ /* Start the scheduler, the heart of the SILC client. When this returns
+ the program will be terminated. */
+ silc_schedule();
+}
+
+/* Creates the main window used in SILC client. This is called always
+ at the initialization of the client. If user wants to create more
+ than one windows a new windows are always created by calling
+ silc_client_add_window. */
+
+SilcClientWindow silc_client_create_main_window(SilcClient client)
+{
+ SilcClientWindow win;
+ void *screen;
+
+ SILC_LOG_DEBUG(("Creating main window"));
+
+ assert(client->screen != NULL);
+
+ win = silc_calloc(1, sizeof(*win));
+ if (win == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new window"));
+ return NULL;
+ }
+
+ client->screen->u_stat_line.program_name = silc_name;
+ client->screen->u_stat_line.program_version = silc_version;
+
+ /* Add the pointers */
+ win->nickname = silc_get_username();
+ win->local_id = NULL;
+ win->local_id_data = NULL;
+ win->local_id_data_len = 0;
+ win->remote_host = NULL;
+ win->remote_port = -1;
+ win->sock = NULL;
+
+ /* Create the actual screen */
+ screen = (void *)silc_screen_create_output_window(client->screen);
+ silc_screen_create_input_window(client->screen);
+ silc_screen_init_upper_status_line(client->screen);
+ silc_screen_init_output_status_line(client->screen);
+ win->screen = screen;
+
+ client->screen->bottom_line->nickname = win->nickname;
+ silc_screen_print_bottom_line(client->screen, 0);
+
+ /* Add the window to windows table */
+ client->windows = silc_calloc(1, sizeof(*client->windows));
+ client->windows[client->windows_count] = win;
+ client->windows_count = 1;
+
+ /* Automatically becomes the current active window */
+ client->current_win = win;
+
+ return win;
+}
+
+/* Allocates and adds new window to the client. This allocates new
+ physical window and internal window for connection specific data.
+ All the connection specific data is always saved into a window
+ since connection is always associated to a active window. */
+
+SilcClientWindow silc_client_add_window(SilcClient client,
+ int is_current)
+{
+ SilcClientWindow win;
+
+ assert(client->screen != NULL);
+
+ win = silc_calloc(1, sizeof(*win));
+ if (win == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new window"));
+ return NULL;
+ }
+
+ /* Add the pointers */
+ win->screen = silc_screen_add_output_window(client->screen);
+ win->sock = NULL;
+
+ /* Add the window to windows table */
+ client->windows = silc_realloc(client->windows, sizeof(*client->windows)
+ * (client->windows_count + 1));
+ client->windows[client->windows_count] = win;
+ client->windows_count++;
+
+ if (is_current == TRUE)
+ client->current_win = win;
+
+ return win;
+}
+
+/* The main task on SILC client. This processes the key pressings user
+ has made. */
+
+SILC_TASK_CALLBACK(silc_client_process_key_press)
+{
+ SilcClient client = (SilcClient)context;
+ int c;
+
+ /* There is data pending in stdin, this gets it directly */
+ c = wgetch(client->screen->input_win);
+ if (silc_client_bad_keys(c))
+ return;
+
+ SILC_LOG_DEBUG(("Pressed key: %d", c));
+
+ switch(c) {
+ /*
+ * Special character handling
+ */
+ case KEY_UP:
+ case KEY_DOWN:
+ break;
+ case KEY_RIGHT:
+ /* Right arrow */
+ SILC_LOG_DEBUG(("RIGHT"));
+ silc_screen_input_cursor_right(client->screen);
+ break;
+ case KEY_LEFT:
+ /* Left arrow */
+ SILC_LOG_DEBUG(("LEFT"));
+ silc_screen_input_cursor_left(client->screen);
+ break;
+ case KEY_BACKSPACE:
+ case KEY_DC:
+ case '\177':
+ case '\b':
+ /* Backspace */
+ silc_screen_input_backspace(client->screen);
+ break;
+ case '\011':
+ /* Tabulator */
+ break;
+ case KEY_IC:
+ /* Insert switch. Turns on/off insert on input window */
+ silc_screen_input_insert(client->screen);
+ break;
+ case CTRL('j'):
+ case '\r':
+ /* Enter, Return. User pressed enter we are ready to
+ process the message. */
+ silc_client_process_message(client);
+ silc_screen_input_reset(client->screen);
+ break;
+ case CTRL('l'):
+ /* Refresh screen, Ctrl^l */
+ silc_screen_refresh_all(client->screen);
+ break;
+ case CTRL('a'):
+ case KEY_HOME:
+ case KEY_BEG:
+ /* Beginning, Home */
+ silc_screen_input_cursor_home(client->screen);
+ break;
+ case CTRL('e'):
+ case KEY_END:
+ /* End */
+ silc_screen_input_cursor_end(client->screen);
+ break;
+ case KEY_LL:
+ /* End */
+ break;
+ case CTRL('g'):
+ /* Bell, Ctrl^g */
+ beep();
+ break;
+ case KEY_DL:
+ case CTRL('u'):
+ /* Delete line */
+ break;
+ default:
+ /*
+ * Other characters
+ */
+ if (c < 32) {
+ /* Control codes are printed as reversed */
+ c = (c & 127) | 64;
+ wattron(client->screen->input_win, A_REVERSE);
+ silc_screen_input_print(client->screen, c);
+ wattroff(client->screen->input_win, A_REVERSE);
+ } else {
+ /* Normal character */
+ silc_screen_input_print(client->screen, c);
+ }
+ }
+
+ silc_screen_print_coordinates(client->screen, 0);
+ silc_screen_refresh_win(client->screen->input_win);
+}
+
+static int silc_client_bad_keys(unsigned char key)
+{
+ /* these are explained in curses.h */
+ switch(key) {
+ case KEY_SF:
+ case KEY_SR:
+ case KEY_NPAGE:
+ case KEY_PPAGE:
+ case KEY_PRINT:
+ case KEY_A1:
+ case KEY_A3:
+ case KEY_B2:
+ case KEY_C1:
+ case KEY_C3:
+ case KEY_UNDO:
+ case KEY_EXIT:
+ case '\v': /* VT */
+ case '\E': /* we ignore ESC */
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* Processes messages user has typed on the screen. This either sends
+ a packet out to network or if command were written executes it. */
+
+static void silc_client_process_message(SilcClient client)
+{
+ unsigned char *data;
+ unsigned int len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ data = client->input_buffer->data;
+ len = strlen(data);
+
+ if (data[0] == '/' && data[1] != ' ') {
+ /* Command */
+ unsigned int argc = 0;
+ unsigned char **argv, *tmpcmd;
+ unsigned int *argv_lens, *argv_types;
+ SilcClientCommand *cmd;
+ SilcClientCommandContext ctx;
+
+ /* Get the command */
+ tmpcmd = silc_client_parse_command(data);
+
+ /* Find command match */
+ for (cmd = silc_command_list; cmd->name; cmd++) {
+ if (!strcmp(cmd->name, tmpcmd))
+ break;
+ }
+
+ if (cmd->name == NULL) {
+ silc_say(client, "Invalid command: %s", tmpcmd);
+ silc_free(tmpcmd);
+ goto out;
+ }
+
+ /* Now parse all arguments */
+ silc_client_parse_command_line(data, &argv, &argv_lens,
+ &argv_types, &argc, cmd->max_args);
+ silc_free(tmpcmd);
+
+ SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
+
+ /* Allocate command context. This and its internals must be free'd
+ by the command routine receiving it. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->sock = client->current_win->sock;
+ ctx->argc = argc;
+ ctx->argv = argv;
+ ctx->argv_lens = argv_lens;
+ ctx->argv_types = argv_types;
+
+ /* Execute command */
+ (*cmd->cb)(ctx);
+
+ } else {
+ /* Normal message to a channel */
+ if (len && client->current_win->current_channel &&
+ client->current_win->current_channel->on_channel == TRUE) {
+ silc_print(client, "> %s", data);
+ silc_client_packet_send_to_channel(client,
+ client->current_win->sock,
+ client->current_win->current_channel,
+ data, strlen(data), TRUE);
+ }
+ }
+
+ out:
+ /* Clear the input buffer */
+ silc_buffer_clear(client->input_buffer);
+ silc_buffer_pull_tail(client->input_buffer,
+ SILC_BUFFER_END(client->input_buffer));
+}
+
+/* Returns the command fetched from user typed command line */
+
+static char *silc_client_parse_command(unsigned char *buffer)
+{
+ char *ret;
+ const char *cp = buffer;
+ int len;
+
+ len = strcspn(cp, " ");
+ ret = silc_to_upper((char *)++cp);
+ ret[len - 1] = 0;
+
+ return ret;
+}
+
+/* Parses user typed command line. At most `max_args' is taken. Rest
+ of the line will be allocated as the last argument if there are more
+ than `max_args' arguments in the line. Note that the command name
+ is counted as one argument and is saved. */
+
+void silc_client_parse_command_line(unsigned char *buffer,
+ unsigned char ***parsed,
+ unsigned int **parsed_lens,
+ unsigned int **parsed_types,
+ unsigned int *parsed_num,
+ unsigned int max_args)
+{
+ int i, len = 0;
+ int argc = 0;
+ const char *cp = buffer;
+
+ /* Take the '/' away */
+ cp++;
+
+ *parsed = silc_calloc(1, sizeof(**parsed));
+ *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
+
+ /* Get the command first */
+ len = strcspn(cp, " ");
+ (*parsed)[0] = silc_to_upper((char *)cp);
+ (*parsed_lens)[0] = len;
+ cp += len + 1;
+ argc++;
+
+ /* Parse arguments */
+ if (strchr(cp, ' ') || strlen(cp) != 0) {
+ for (i = 1; i < max_args; i++) {
+
+ if (i != max_args - 1)
+ len = strcspn(cp, " ");
+ else
+ len = strlen(cp);
+
+ *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
+ *parsed_lens = silc_realloc(*parsed_lens,
+ sizeof(**parsed_lens) * (argc + 1));
+ (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
+ memcpy((*parsed)[argc], cp, len);
+ (*parsed_lens)[argc] = len;
+ argc++;
+
+ cp += len;
+ if (strlen(cp) == 0)
+ break;
+ else
+ cp++;
+ }
+ }
+
+ /* Save argument types. Protocol defines all argument types but
+ this implementation makes sure that they are always in correct
+ order hence this simple code. */
+ *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
+ for (i = 0; i < argc; i++)
+ (*parsed_types)[i] = i;
+
+ *parsed_num = argc;
+}
+
+/* Updates clock on the screen every minute. */
+
+SILC_TASK_CALLBACK(silc_client_update_clock)
+{
+ SilcClient client = (SilcClient)context;
+
+ /* Update the clock on the screen */
+ silc_screen_print_clock(client->screen);
+
+ /* Re-register this same task */
+ silc_task_register(qptr, 0, silc_client_update_clock, context,
+ silc_client_time_til_next_min(), 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
+ silc_screen_refresh_win(client->screen->input_win);
+}
+
+/* Runs commands user configured in configuration file. This is
+ called when initializing client. */
+
+SILC_TASK_CALLBACK(silc_client_run_commands)
+{
+ SilcClient client = (SilcClient)context;
+ SilcClientConfigSectionCommand *cs;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ cs = client->config->commands;
+ while(cs) {
+ unsigned int argc = 0;
+ unsigned char **argv, *tmpcmd;
+ unsigned int *argv_lens, *argv_types;
+ SilcClientCommand *cmd;
+ SilcClientCommandContext ctx;
+
+ /* Get the command */
+ tmpcmd = silc_client_parse_command(cs->command);
+
+ for (cmd = silc_command_list; cmd->name; cmd++) {
+ if (!strcmp(cmd->name, tmpcmd))
+ break;
+ }
+
+ if (cmd->name == NULL) {
+ silc_say(client, "Invalid command: %s", tmpcmd);
+ silc_free(tmpcmd);
+ continue;
+ }
+
+ /* Now parse all arguments */
+ silc_client_parse_command_line(cs->command, &argv, &argv_lens,
+ &argv_types, &argc, cmd->max_args);
+ silc_free(tmpcmd);
+
+ SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
+
+ /* Allocate command context. This and its internals must be free'd
+ by the command routine receiving it. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->sock = client->current_win->sock;
+ ctx->argc = argc;
+ ctx->argv = argv;
+ ctx->argv_lens = argv_lens;
+ ctx->argv_types = argv_types;
+
+ /* Execute command */
+ (*cmd->cb)(ctx);
+
+ cs = cs->next;
+ }
+}
+
+/* Internal context for connection process. This is needed as we
+ doing asynchronous connecting. */
+typedef struct {
+ SilcClient client;
+ SilcTask task;
+ int sock;
+ char *host;
+ int port;
+ int tries;
+} SilcClientInternalConnectContext;
+
+static int
+silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
+{
+ int sock;
+
+ /* XXX In the future we should give up this non-blocking connect all
+ together and use threads instead. */
+ /* Create connection to server asynchronously */
+ sock = silc_net_create_connection_async(ctx->port, ctx->host);
+ if (sock < 0)
+ return -1;
+
+ /* Register task that will receive the async connect and will
+ read the result. */
+ ctx->task = silc_task_register(ctx->client->io_queue, sock,
+ silc_client_connect_to_server_start,
+ (void *)ctx, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
+ silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
+ silc_schedule_set_listen_fd(sock, ctx->task->iomask);
+
+ ctx->sock = sock;
+
+ return sock;
+}
+
+/* Connects to remote server */
+
+int silc_client_connect_to_server(SilcClient client, int port,
+ char *host)
+{
+ SilcClientInternalConnectContext *ctx;
+
+ SILC_LOG_DEBUG(("Connecting to port %d of server %s",
+ port, host));
+
+ silc_say(client, "Connecting to port %d of server %s", port, host);
+
+ client->current_win->remote_host = strdup(host);
+ client->current_win->remote_port = port;
+
+ /* Allocate internal context for connection process. This is
+ needed as we are doing async connecting. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->host = strdup(host);
+ ctx->port = port;
+ ctx->tries = 0;
+
+ /* Do the actual connecting process */
+ return silc_client_connect_to_server_internal(ctx);
+}
+
+/* Start of the connection to the remote server. This is called after
+ succesful TCP/IP connection has been established to the remote host. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
+{
+ SilcClientInternalConnectContext *ctx =
+ (SilcClientInternalConnectContext *)context;
+ SilcClient client = ctx->client;
+ SilcProtocol protocol;
+ SilcClientKEInternalContext *proto_ctx;
+ int opt, opt_len = sizeof(opt);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Check the socket status as it might be in error */
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
+ if (opt != 0) {
+ if (ctx->tries < 2) {
+ /* Connection failed but lets try again */
+ silc_say(ctx->client, "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
+ silc_say(client, "Connecting to port %d of server %s resumed",
+ ctx->port, ctx->host);
+
+ /* Unregister old connection try */
+ silc_schedule_unset_listen_fd(fd);
+ silc_net_close_connection(fd);
+ silc_task_unregister(client->io_queue, ctx->task);
+
+ /* Try again */
+ silc_client_connect_to_server_internal(ctx);
+ ctx->tries++;
+ } else {
+ /* Connection failed and we won't try anymore */
+ silc_say(ctx->client, "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
+ silc_schedule_unset_listen_fd(fd);
+ silc_net_close_connection(fd);
+ silc_task_unregister(client->io_queue, ctx->task);
+ silc_free(ctx);
+ }
+ return;
+ }
+
+ silc_schedule_unset_listen_fd(fd);
+ silc_task_unregister(client->io_queue, ctx->task);
+ silc_free(ctx);
+
+ /* Allocate new socket connection object */
+ silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER,
+ (void *)client->current_win,
+ &client->current_win->sock);
+ if (client->current_win->sock == NULL) {
+ silc_say(client, "Error: Could not allocate connection socket");
+ silc_net_close_connection(fd);
+ return;
+ }
+ client->current_win->sock->hostname = client->current_win->remote_host;
+ client->current_win->sock->port = client->current_win->remote_port;
+
+ /* Allocate internal Key Exchange context. This is sent to the
+ protocol as context. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = client->current_win->sock;
+ proto_ctx->rng = client->rng;
+ proto_ctx->responder = FALSE;
+
+ /* Perform key exchange protocol. silc_client_connect_to_server_final
+ will be called after the protocol is finished. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ &protocol, (void *)proto_ctx,
+ silc_client_connect_to_server_second);
+ if (!protocol) {
+ silc_say(client, "Error: Could not start authentication protocol");
+ return;
+ }
+ client->current_win->sock->protocol = protocol;
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it will
+ be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)client;
+ SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
+
+ /* Execute the protocol */
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+}
+
+/* Second part of the connecting to the server. This executed
+ authentication protocol. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcSocketConnection sock = NULL;
+ SilcClientConnAuthInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ /* Error occured during protocol */
+ SILC_LOG_DEBUG(("Error during KE protocol"));
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ sock->protocol = NULL;
+ return;
+ }
+
+ /* Allocate internal context for the authentication protocol. This
+ is sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = sock = ctx->sock;
+ proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
+
+ /* Resolve the authentication method to be used in this connection */
+ proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+ if (client->config->conns) {
+ SilcClientConfigSectionConnection *conn = NULL;
+
+ /* Check if we find a match from user configured connections */
+ conn = silc_client_config_find_connection(client->config,
+ sock->hostname,
+ sock->port);
+ if (conn) {
+ /* Match found. Use the configured authentication method */
+ proto_ctx->auth_meth = conn->auth_meth;
+ if (conn->auth_data) {
+ proto_ctx->auth_data = strdup(conn->auth_data);
+ proto_ctx->auth_data_len = strlen(conn->auth_data);
+ }
+ } else {
+ /* No match found. Resolve by sending AUTH_REQUEST to server */
+ proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+ }
+ } else {
+ /* XXX Resolve by sending AUTH_REQUEST to server */
+ proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+ }
+
+ /* Free old protocol as it is finished now */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ silc_free(ctx);
+ /* silc_free(ctx->keymat....); */
+ sock->protocol = NULL;
+
+ /* Allocate the authentication protocol. This is allocated here
+ but we won't start it yet. We will be receiving party of this
+ protocol thus we will wait that connecting party will make
+ their first move. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+ &sock->protocol, (void *)proto_ctx,
+ silc_client_connect_to_server_final);
+
+ /* Execute the protocol */
+ sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
+}
+
+/* Finalizes the connection to the remote SILC server. This is called
+ after authentication protocol has been completed. This send our
+ user information to the server to receive our client ID from
+ server. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientConnAuthInternalContext *ctx =
+ (SilcClientConnAuthInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientWindow win = (SilcClientWindow)ctx->sock->user_data;
+ SilcBuffer packet;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ /* Error occured during protocol */
+ SILC_LOG_DEBUG(("Error during authentication protocol"));
+ silc_protocol_free(protocol);
+ if (ctx->auth_data)
+ silc_free(ctx->auth_data);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ win->sock->protocol = NULL;
+ return;
+ }
+
+ /* Send NEW_CLIENT packet to the server. We will become registered
+ to the SILC network after sending this packet and we will receive
+ client ID from the server. */
+ packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
+ strlen(client->realname));
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(strlen(client->username)),
+ SILC_STR_UI_XNSTRING(client->username,
+ strlen(client->username)),
+ SILC_STR_UI_SHORT(strlen(client->realname)),
+ SILC_STR_UI_XNSTRING(client->realname,
+ strlen(client->realname)),
+ SILC_STR_END);
+
+ /* Send the packet */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+
+ silc_say(client, "Connected to port %d of host %s",
+ win->remote_port, win->remote_host);
+
+ client->screen->bottom_line->connection = win->remote_host;
+ silc_screen_print_bottom_line(client->screen, 0);
+
+ silc_protocol_free(protocol);
+ if (ctx->auth_data)
+ silc_free(ctx->auth_data);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ win->sock->protocol = NULL;
+}
+
+typedef struct {
+ SilcPacketContext *packetdata;
+ SilcSocketConnection sock;
+ SilcClient client;
+} SilcClientInternalPacket;
+
+SILC_TASK_CALLBACK(silc_client_packet_process)
+{
+ SilcClient client = (SilcClient)context;
+ SilcSocketConnection sock = NULL;
+ int ret, packetlen, paddedlen;
+
+ SILC_LOG_DEBUG(("Processing packet"));
+
+ SILC_CLIENT_GET_SOCK(client, fd, sock);
+ if (sock == NULL)
+ return;
+
+ /* Packet sending */
+ if (type == SILC_TASK_WRITE) {
+ SILC_LOG_DEBUG(("Writing data to connection"));
+
+ if (sock->outbuf->data - sock->outbuf->head)
+ silc_buffer_push(sock->outbuf,
+ sock->outbuf->data - sock->outbuf->head);
+
+ /* Write the packet out to the connection */
+ ret = silc_packet_write(fd, sock->outbuf);
+
+ /* If returned -2 could not write to connection now, will do
+ it later. */
+ if (ret == -2)
+ return;
+
+ /* Error */
+ if (ret == -1)
+ SILC_LOG_ERROR(("Packet dropped"));
+
+ /* The packet has been sent and now it is time to set the connection
+ back to only for input. When there is again some outgoing data
+ available for this connection it will be set for output as well.
+ This call clears the output setting and sets it only for input. */
+ SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+
+ return;
+ }
+
+ /* Packet receiving */
+ if (type == SILC_TASK_READ) {
+ SILC_LOG_DEBUG(("Reading data from connection"));
+
+ /* Allocate the incoming data buffer if not done already. */
+ if (!sock->inbuf)
+ sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+
+ /* Read some data from connection */
+ ret = silc_packet_read(fd, sock->inbuf);
+
+ /* If returned -2 data was not available now, will read it later. */
+ if (ret == -2)
+ return;
+
+ /* Error */
+ if (ret == -1) {
+ SILC_LOG_ERROR(("Packet dropped"));
+ return;
+ }
+
+ /* EOF */
+ if (ret == 0) {
+ SILC_LOG_DEBUG(("Read EOF"));
+
+ /* If connection is disconnecting already we will finally
+ close the connection */
+ if (SILC_IS_DISCONNECTING(sock)) {
+ silc_client_close_connection(client, sock);
+ return;
+ }
+
+ silc_say(client, "Connection closed: premature EOF");
+ SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+
+ silc_client_close_connection(client, sock);
+ return;
+ }
+
+ /* Check whether we received a whole packet. If reading went without
+ errors we either read a whole packet or the read packet is
+ incorrect and will be dropped. */
+ SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+ if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
+ SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+ silc_buffer_clear(sock->inbuf);
+ return;
+ }
+
+ /* Decrypt a packet coming from server connection */
+ if (sock->type == SILC_SOCKET_TYPE_SERVER ||
+ sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ SilcClientInternalPacket *packet;
+ int mac_len = 0;
+
+ if (win->hmac)
+ mac_len = win->hmac->hash->hash->hash_len;
+
+ if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
+ /* Received possibly many packets at once */
+
+ while(sock->inbuf->len > 0) {
+ SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+ if (sock->inbuf->len < paddedlen) {
+ SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+ return;
+ }
+
+ paddedlen += 2;
+ packet = silc_calloc(1, sizeof(*packet));
+ packet->client = client;
+ packet->sock = sock;
+ packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+ packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
+ silc_buffer_pull_tail(packet->packetdata->buffer,
+ SILC_BUFFER_END(packet->packetdata->buffer));
+ silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data,
+ paddedlen + mac_len);
+
+ SILC_LOG_HEXDUMP(("Incoming packet, len %d",
+ packet->packetdata->buffer->len),
+ packet->packetdata->buffer->data,
+ packet->packetdata->buffer->len);
+ SILC_LOG_DEBUG(("Packet from server %s, "
+ "server type %d, packet length %d",
+ win->remote_host, win->remote_type, paddedlen));
+
+ /* If this packet is for the current active connection we will
+ parse the packet right away to get it quickly on the screen.
+ Otherwise, it will be parsed with a timeout as the data is
+ for inactive window (which might not be visible at all). */
+ if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) {
+ /* Parse it real soon */
+ silc_task_register(client->timeout_queue, fd,
+ silc_client_packet_parse,
+ (void *)packet, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ } else {
+ /* Parse the packet with timeout */
+ silc_task_register(client->timeout_queue, fd,
+ silc_client_packet_parse,
+ (void *)packet, 0, 200000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
+
+ /* Pull the packet from inbuf thus we'll get the next one
+ in the inbuf. */
+ silc_buffer_pull(sock->inbuf, paddedlen);
+ if (win->hmac)
+ silc_buffer_pull(sock->inbuf, mac_len);
+ }
+ silc_buffer_clear(sock->inbuf);
+ return;
+ } else {
+ /* Received one packet */
+
+ SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
+ sock->inbuf->data, sock->inbuf->len);
+ SILC_LOG_DEBUG(("Packet from server %s, "
+ "server type %d, packet length %d",
+ win->remote_host, win->remote_type, paddedlen));
+
+ packet = silc_calloc(1, sizeof(*packet));
+ packet->client = client;
+ packet->sock = sock;
+ packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+ packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+ silc_buffer_clear(sock->inbuf);
+
+ /* If this packet is for the current active connection we will
+ parse the packet right away to get it quickly on the screen.
+ Otherwise, it will be parsed with a timeout as the data is
+ for inactive window (which might not be visible at all). */
+ if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) {
+ /* Parse it real soon */
+ silc_task_register(client->timeout_queue, fd,
+ silc_client_packet_parse,
+ (void *)packet, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ } else {
+ /* Parse the packet with timeout */
+ silc_task_register(client->timeout_queue, fd,
+ silc_client_packet_parse,
+ (void *)packet, 0, 200000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+ }
+ }
+ }
+
+ SILC_LOG_ERROR(("Weird, nothing happened - ignoring"));
+}
+
+/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
+ after packet has been totally decrypted and parsed. */
+
+static int silc_client_packet_check_mac(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+
+ /* Check MAC */
+ if (win->hmac) {
+ int headlen = buffer->data - buffer->head, mac_len;
+ unsigned char *packet_mac, mac[32];
+
+ SILC_LOG_DEBUG(("Verifying MAC"));
+
+ mac_len = win->hmac->hash->hash->hash_len;
+
+ silc_buffer_push(buffer, headlen);
+
+ /* Take mac from packet */
+ packet_mac = buffer->tail;
+
+ /* Make MAC and compare */
+ memset(mac, 0, sizeof(mac));
+ silc_hmac_make_with_key(win->hmac,
+ buffer->data, buffer->len,
+ win->hmac_key, win->hmac_key_len, mac);
+#if 0
+ SILC_LOG_HEXDUMP(("PMAC"), packet_mac, mac_len);
+ SILC_LOG_HEXDUMP(("CMAC"), mac, mac_len);
+#endif
+ if (memcmp(mac, packet_mac, mac_len)) {
+ SILC_LOG_DEBUG(("MAC failed"));
+ return FALSE;
+ }
+
+ SILC_LOG_DEBUG(("MAC is Ok"));
+ memset(mac, 0, sizeof(mac));
+
+ silc_buffer_pull(buffer, headlen);
+ }
+
+ return TRUE;
+}
+
+/* Decrypts rest of the packet (after decrypting just the SILC header).
+ After calling this function the packet is ready to be parsed by calling
+ silc_packet_parse. */
+
+static int silc_client_packet_decrypt_rest(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ unsigned int mac_len = 0;
+
+ /* Decrypt */
+ if (win && win->receive_key) {
+
+ /* Pull MAC from packet before decryption */
+ if (win->hmac) {
+ mac_len = win->hmac->hash->hash->hash_len;
+ if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+ silc_buffer_push_tail(buffer, mac_len);
+ } else {
+ SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+ return FALSE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("Decrypting rest of the packet"));
+
+ /* Decrypt rest of the packet */
+ silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+ silc_packet_decrypt(win->receive_key, buffer, buffer->len);
+ silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+
+ SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
+ buffer->data, buffer->len);
+ }
+
+ return TRUE;
+}
+
+/* Decrypts rest of the SILC Packet header that has been decrypted partly
+ already. This decrypts the padding of the packet also. After calling
+ this function the packet is ready to be parsed by calling function
+ silc_packet_parse. This is used in special packet reception. */
+
+static int silc_client_packet_decrypt_rest_special(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ unsigned int mac_len = 0;
+
+ /* Decrypt rest of the header plus padding */
+ if (win && win->receive_key) {
+ unsigned short truelen, len1, len2, padlen;
+
+ /* Pull MAC from packet before decryption */
+ if (win->hmac) {
+ mac_len = win->hmac->hash->hash->hash_len;
+ if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+ silc_buffer_push_tail(buffer, mac_len);
+ } else {
+ SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+ return FALSE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("Decrypting rest of the header"));
+
+ SILC_GET16_MSB(len1, &buffer->data[4]);
+ SILC_GET16_MSB(len2, &buffer->data[6]);
+
+ truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
+ padlen = SILC_PACKET_PADLEN(truelen);
+ len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
+
+ silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+ SILC_LOG_HEXDUMP(("XXX"), buffer->data, buffer->len);
+ silc_packet_decrypt(win->receive_key, buffer, len1);
+ silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+ SILC_LOG_HEXDUMP(("XXX"), buffer->data, buffer->len);
+ }
+
+ return TRUE;
+}
+
+/* Parses whole packet, received earlier. */
+
+SILC_TASK_CALLBACK(silc_client_packet_parse)
+{
+ SilcClientInternalPacket *packet = (SilcClientInternalPacket *)context;
+ SilcBuffer buffer = packet->packetdata->buffer;
+ SilcClient client = packet->client;
+ SilcSocketConnection sock = packet->sock;
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ int ret;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decrypt start of the packet header */
+ if (win && win->receive_key)
+ silc_packet_decrypt(win->receive_key, buffer, SILC_PACKET_MIN_HEADER_LEN);
+
+ /* If the packet type is not any special type lets decrypt rest
+ of the packet here. */
+ if (buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE &&
+ buffer->data[3] != SILC_PACKET_PRIVATE_MESSAGE) {
+ normal:
+ /* Normal packet, decrypt rest of the packet */
+ if (!silc_client_packet_decrypt_rest(client, sock, buffer))
+ goto out;
+
+ /* Parse the packet. Packet type is returned. */
+ ret = silc_packet_parse(packet->packetdata);
+ if (ret == SILC_PACKET_NONE)
+ goto out;
+
+ /* Check MAC */
+ if (!silc_client_packet_check_mac(client, sock, buffer))
+ goto out;
+ } else {
+ /* If private message key is not set for private message it is
+ handled as normal packet. Go back up. */
+ if (buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+ !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+ goto normal;
+
+ /* Packet requires special handling, decrypt rest of the header.
+ This only decrypts. This does not do any MAC checking, it must
+ be done individually later when doing the special processing. */
+ silc_client_packet_decrypt_rest_special(client, sock, buffer);
+
+ /* Parse the packet header in special way as this is "special"
+ packet type. */
+ ret = silc_packet_parse_special(packet->packetdata);
+ if (ret == SILC_PACKET_NONE)
+ goto out;
+ }
+
+ /* Parse the incoming packet type */
+ silc_client_packet_parse_type(client, sock, packet->packetdata);
+
+ out:
+ silc_buffer_clear(packet->packetdata->buffer);
+ silc_free(packet->packetdata);
+ silc_free(packet);
+}
+
+/* Parses the packet type and calls what ever routines the packet type
+ requires. This is done for all incoming packets. */
+
+void silc_client_packet_parse_type(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcPacketType type = packet->type;
+
+ SILC_LOG_DEBUG(("Parsing packet type %d", type));
+
+ /* Parse the packet type */
+ switch(type) {
+ case SILC_PACKET_DISCONNECT:
+ silc_client_disconnected_by_server(client, sock, buffer);
+ break;
+ case SILC_PACKET_SUCCESS:
+ /*
+ * Success received for something. For now we can have only
+ * one protocol for connection executing at once hence this
+ * success message is for whatever protocol is executing currently.
+ */
+ if (sock->protocol) {
+ sock->protocol->execute(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ }
+ break;
+ case SILC_PACKET_FAILURE:
+ /*
+ * Failure received for some protocol. Set the protocol state to
+ * error and call the protocol callback. This fill cause error on
+ * protocol and it will call the final callback.
+ */
+ if (sock->protocol) {
+ sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ sock->protocol->execute(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ }
+ break;
+ case SILC_PACKET_REJECT:
+ break;
+
+ case SILC_PACKET_NOTIFY:
+ /*
+ * Received notify message
+ */
+ silc_client_notify_by_server(client, sock, buffer);
+ break;
+
+ case SILC_PACKET_ERROR:
+ /*
+ * Received error message
+ */
+ silc_client_error_by_server(client, sock, buffer);
+ break;
+
+ case SILC_PACKET_CHANNEL_MESSAGE:
+ /*
+ * Received message to (from, actually) a channel
+ */
+ silc_client_channel_message(client, sock, packet);
+ break;
+ case SILC_PACKET_CHANNEL_KEY:
+ /*
+ * Received key for a channel. By receiving this key the client will be
+ * able to talk to the channel it has just joined. This can also be
+ * a new key for existing channel as keys expire peridiocally.
+ */
+ silc_client_receive_channel_key(client, sock, buffer);
+ break;
+
+ case SILC_PACKET_PRIVATE_MESSAGE:
+ /*
+ * Received private message
+ */
+ {
+ SilcClientCommandReplyContext ctx;
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->sock = sock;
+ ctx->context = buffer; /* kludge */
+ silc_client_command_reply_msg((void *)ctx);
+ }
+ break;
+ case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+ /*
+ * Received private message key
+ */
+ break;
+
+ case SILC_PACKET_COMMAND_REPLY:
+ /*
+ * Recived reply for a command
+ */
+ silc_client_command_reply_process(client, sock, buffer);
+ break;
+
+ case SILC_PACKET_KEY_EXCHANGE:
+ if (sock->protocol) {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ proto_ctx->packet = buffer;
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
+ "protocol active, packet dropped."));
+
+ /* XXX Trigger KE protocol?? Rekey actually! */
+ }
+ break;
+
+ case SILC_PACKET_KEY_EXCHANGE_1:
+ if (sock->protocol) {
+
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
+ "protocol active, packet dropped."));
+ }
+ break;
+ case SILC_PACKET_KEY_EXCHANGE_2:
+ if (sock->protocol) {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_buffer_free(proto_ctx->packet);
+
+ proto_ctx->packet = buffer;
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
+ "protocol active, packet dropped."));
+ }
+ break;
+
+ case SILC_PACKET_NEW_ID:
+ {
+ /*
+ * Received new ID from server. This packet is received at
+ * the connection to the server. New ID is also received when
+ * user changes nickname but in that case the new ID is received
+ * as command reply and not as this packet type.
+ */
+ unsigned char *id_string;
+ unsigned short id_type;
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&id_type),
+ SILC_STR_UI16_STRING_ALLOC(&id_string),
+ SILC_STR_END);
+
+ if ((SilcIdType)id_type != SILC_ID_CLIENT)
+ break;
+
+ silc_client_receive_new_id(client, sock, id_string);
+ silc_free(id_string);
+ break;
+ }
+
+ default:
+ SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
+ break;
+ }
+}
+
+/* Internal routine that sends packet or marks packet to be sent. This
+ is used directly only in special cases. Normal cases should use
+ silc_server_packet_send. Returns < 0 on error. */
+
+static int silc_client_packet_send_real(SilcClient client,
+ SilcSocketConnection sock,
+ int force_send)
+{
+ /* Send now if forced to do so */
+ if (force_send == TRUE) {
+ int ret;
+ SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
+ ret = silc_packet_write(sock->sock, sock->outbuf);
+
+ if (ret == -1)
+ SILC_LOG_ERROR(("Packet dropped"));
+ if (ret != -2)
+ return ret;
+
+ SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
+ }
+
+ SILC_LOG_DEBUG(("Packet in queue"));
+
+ /* Mark that there is some outgoing data available for this connection.
+ This call sets the connection both for input and output (the input
+ is set always and this call keeps the input setting, actually).
+ Actual data sending is performed by silc_client_packet_process. */
+ SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+
+ /* Mark to socket that data is pending in outgoing buffer. This flag
+ is needed if new data is added to the buffer before the earlier
+ put data is sent to the network. */
+ SILC_SET_OUTBUF_PENDING(sock);
+
+ return 0;
+}
+
+/* Prepare outgoing data buffer for packet sending. */
+
+static void silc_client_packet_send_prepare(SilcClient client,
+ SilcSocketConnection sock,
+ unsigned int header_len,
+ unsigned int padlen,
+ unsigned int data_len)
+{
+ int totlen, oldlen;
+
+ totlen = header_len + padlen + data_len;
+
+ /* Prepare the outgoing buffer for packet sending. */
+ if (!sock->outbuf) {
+ /* Allocate new buffer. This is done only once per connection. */
+ SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
+
+ sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+ silc_buffer_pull_tail(sock->outbuf, totlen);
+ silc_buffer_pull(sock->outbuf, header_len + padlen);
+ } else {
+ if (SILC_IS_OUTBUF_PENDING(sock)) {
+ /* There is some pending data in the buffer. */
+
+ if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
+ SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+ /* XXX: not done yet */
+ }
+ oldlen = sock->outbuf->len;
+ silc_buffer_pull_tail(sock->outbuf, totlen);
+ silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
+ } else {
+ /* Buffer is free for use */
+ silc_buffer_clear(sock->outbuf);
+ silc_buffer_pull_tail(sock->outbuf, totlen);
+ silc_buffer_pull(sock->outbuf, header_len + padlen);
+ }
+ }
+}
+
+/* Sends packet. This doesn't actually send the packet instead it assembles
+ it and marks it to be sent. However, if force_send is TRUE the packet
+ is sent immediately. if dst_id, cipher and hmac are NULL those parameters
+ will be derived from sock argument. Otherwise the valid arguments sent
+ are used. */
+
+void silc_client_packet_send(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ SilcPacketContext packetdata;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+ /* Get data used in the packet sending, keys and stuff */
+ if ((!cipher || !hmac || !dst_id) && sock->user_data) {
+ if (!cipher && ((SilcClientWindow)sock->user_data)->send_key)
+ cipher = ((SilcClientWindow)sock->user_data)->send_key;
+ if (!hmac && ((SilcClientWindow)sock->user_data)->hmac) {
+ hmac = ((SilcClientWindow)sock->user_data)->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = ((SilcClientWindow)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcClientWindow)sock->user_data)->hmac_key_len;
+ }
+ if (!dst_id && ((SilcClientWindow)sock->user_data)->remote_id) {
+ dst_id = ((SilcClientWindow)sock->user_data)->remote_id;
+ dst_id_type = SILC_ID_SERVER;
+ }
+ }
+
+ /* Set the packet context pointers */
+ packetdata.flags = 0;
+ packetdata.type = type;
+ if (((SilcClientWindow)sock->user_data)->local_id_data)
+ packetdata.src_id = ((SilcClientWindow)sock->user_data)->local_id_data;
+ else
+ packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
+ packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.src_id_type = SILC_ID_CLIENT;
+ if (dst_id) {
+ packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
+ packetdata.dst_id_len = silc_id_get_len(dst_id_type);
+ packetdata.dst_id_type = dst_id_type;
+ } else {
+ packetdata.dst_id = NULL;
+ packetdata.dst_id_len = 0;
+ packetdata.dst_id_type = SILC_ID_NONE;
+ }
+ packetdata.rng = client->rng;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_client_packet_send_prepare(client, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+
+ SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the data to the buffer */
+ if (data && data_len)
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet */
+ if (hmac) {
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+ }
+
+ /* Encrypt the packet */
+ if (cipher)
+ silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
+
+ /* Pull MAC into the visible data area */
+ if (hmac)
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_client_packet_send_real(client, sock, force_send);
+}
+
+/* Sends packet to a channel. Packet to channel is always encrypted
+ differently from "normal" packets. SILC header of the packet is
+ encrypted with the next receiver's key and the rest of the packet is
+ encrypted with the channel specific key. Padding and HMAC is computed
+ with the next receiver's key. */
+
+void silc_client_packet_send_to_channel(SilcClient client,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ int i;
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ SilcBuffer payload;
+ SilcPacketContext packetdata;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+ unsigned char *id_string;
+ SilcCipher cipher;
+ SilcHmac hmac;
+
+ SILC_LOG_DEBUG(("Sending packet to channel"));
+
+ if (!channel || !channel->key) {
+ silc_say(client, "Cannot talk to channel: key does not exist");
+ return;
+ }
+
+ /* Generate IV */
+ if (!channel->iv)
+ for (i = 0; i < 16; i++)
+ channel->iv[i] = silc_rng_get_byte(client->rng);
+ else
+ silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
+
+ /* Encode the channel payload */
+ payload = silc_channel_encode_payload(strlen(win->nickname), win->nickname,
+ data_len, data, 16, channel->iv,
+ client->rng);
+ if (!payload) {
+ silc_say(client,
+ "Error: Could not create packet to be sent to the channel");
+ return;
+ }
+
+ /* Get data used in packet header encryption, keys and stuff. Rest
+ of the packet (the payload) is, however, encrypted with the
+ specified channel key. */
+ cipher = win->send_key;
+ hmac = win->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = win->hmac_key;
+ hmac_key_len = win->hmac_key_len;
+ id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+
+ /* Set the packet context pointers. The destination ID is always
+ the Channel ID of the channel. Server and router will handle the
+ distribution of the packet. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+ packetdata.src_id = win->local_id_data;
+ packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.src_id_type = SILC_ID_CLIENT;
+ packetdata.dst_id = id_string;
+ packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+ packetdata.dst_id_type = SILC_ID_CHANNEL;
+ packetdata.rng = client->rng;
+ packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len));
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_client_packet_send_prepare(client, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ payload->len);
+
+ packetdata.buffer = sock->outbuf;
+
+ /* Encrypt payload of the packet. This is encrypted with the channel key. */
+ channel->channel_key->cipher->encrypt(channel->channel_key->context,
+ payload->data, payload->data,
+ payload->len - 16, /* -IV_LEN */
+ channel->iv);
+
+ SILC_LOG_HEXDUMP(("XXX"), payload->data, payload->len);
+
+ /* Put the actual encrypted payload data into the buffer. */
+ silc_buffer_put(sock->outbuf, payload->data, payload->len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ SILC_LOG_HEXDUMP(("XXX"), sock->outbuf->data, sock->outbuf->len);
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with our server. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_client_packet_send_real(client, sock, force_send);
+ silc_buffer_free(payload);
+ silc_free(id_string);
+}
+
+/* Sends private message to remote client. If private message key has
+ not been set with this client then the message will be encrypted using
+ normal session keys. Private messages are special packets in SILC
+ network hence we need this own function for them. This is similiar
+ to silc_client_packet_send_to_channel except that we send private
+ message. */
+
+void silc_client_packet_send_private_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcClientEntry client_entry,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ SilcBuffer buffer;
+ SilcPacketContext packetdata;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+ unsigned int nick_len;
+ SilcCipher cipher;
+ SilcHmac hmac;
+
+ SILC_LOG_DEBUG(("Sending private message"));
+
+ /* Create private message payload */
+ nick_len = strlen(client->current_win->nickname);
+ buffer = silc_buffer_alloc(2 + nick_len + data_len);
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(nick_len),
+ SILC_STR_UI_XNSTRING(client->current_win->nickname,
+ nick_len),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_END);
+
+ /* If we don't have private message specific key then private messages
+ are just as any normal packet thus call normal packet sending. If
+ the key exist then the encryption process is a bit different and
+ will be done in the rest of this function. */
+ if (!client_entry->send_key) {
+ silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
+ client_entry->id, SILC_ID_CLIENT, NULL, NULL,
+ buffer->data, buffer->len, force_send);
+ goto out;
+ }
+
+ /* We have private message specific key */
+
+ /* Get data used in the encryption */
+ cipher = client_entry->send_key;
+ hmac = win->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = win->hmac_key;
+ hmac_key_len = win->hmac_key_len;
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
+ packetdata.src_id = win->local_id_data;
+ packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.src_id_type = SILC_ID_CLIENT;
+ if (client_entry)
+ packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
+ else
+ packetdata.dst_id = win->local_id_data;
+ packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.dst_id_type = SILC_ID_CLIENT;
+ packetdata.rng = client->rng;
+ packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len));
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_client_packet_send_prepare(client, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ buffer->len);
+
+ packetdata.buffer = sock->outbuf;
+
+ /* Encrypt payload of the packet. Encrypt with private message specific
+ key if it exist, otherwise with session key. */
+ cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
+ buffer->len, cipher->iv);
+
+ /* Put the actual encrypted payload data into the buffer. */
+ silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ SILC_LOG_HEXDUMP(("XXX"), sock->outbuf->data, sock->outbuf->len);
+
+ /* Encrypt the header and padding of the packet. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_client_packet_send_real(client, sock, force_send);
+ silc_free(packetdata.dst_id);
+
+ out:
+ silc_free(buffer);
+}
+
+/* Closes connection to remote end. Free's all allocated data except
+ for some information such as nickname etc. that are valid at all time. */
+
+void silc_client_close_connection(SilcClient client,
+ SilcSocketConnection sock)
+{
+ SilcClientWindow win;
+ int i;
+
+ /* We won't listen for this connection anymore */
+ silc_schedule_unset_listen_fd(sock->sock);
+
+ /* Unregister all tasks */
+ silc_task_unregister_by_fd(client->io_queue, sock->sock);
+ silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
+
+ /* Close the actual connection */
+ silc_net_close_connection(sock->sock);
+
+ silc_say(client, "Closed connection to host %s", sock->hostname ?
+ sock->hostname : sock->ip);
+
+ /* Free everything */
+ if (sock->user_data) {
+ win = (SilcClientWindow)sock->user_data;
+
+ /* Clear ID caches */
+ for (i = 0; i < 96; i++)
+ silc_idcache_del_all(&win->client_id_cache[i],
+ win->client_id_cache_count[i]);
+ for (i = 0; i < 96; i++)
+ silc_idcache_del_all(&win->channel_id_cache[i],
+ win->channel_id_cache_count[i]);
+
+ /* Free data */
+ if (win->remote_host)
+ silc_free(win->remote_host);
+ if (win->local_id)
+ silc_free(win->local_id);
+ if (win->local_id_data)
+ silc_free(win->local_id_data);
+ if (win->send_key)
+ silc_cipher_free(win->send_key);
+ if (win->receive_key)
+ silc_cipher_free(win->receive_key);
+ if (win->public_key)
+ silc_pkcs_free(win->public_key);
+ if (win->hmac)
+ silc_hmac_free(win->hmac);
+ if (win->hmac_key) {
+ memset(win->hmac_key, 0, win->hmac_key_len);
+ silc_free(win->hmac_key);
+ }
+
+ win->sock = NULL;
+ win->remote_port = 0;
+ win->remote_type = 0;
+ win->send_key = NULL;
+ win->receive_key = NULL;
+ win->public_key = NULL;
+ win->hmac = NULL;
+ win->hmac_key = NULL;
+ win->hmac_key_len = 0;
+ win->local_id = NULL;
+ win->local_id_data = NULL;
+ win->remote_host = NULL;
+ }
+
+ if (sock->protocol) {
+ silc_protocol_free(sock->protocol);
+ sock->protocol = NULL;
+ }
+ silc_socket_free(sock);
+}
+
+/* Called when we receive disconnection packet from server. This
+ closes our end properly and displays the reason of the disconnection
+ on the screen. */
+
+void silc_client_disconnected_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message)
+{
+ char *msg;
+
+ SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
+
+ msg = silc_calloc(message->len + 1, sizeof(char));
+ memcpy(msg, message->data, message->len);
+ silc_say(client, msg);
+ silc_free(msg);
+
+ SILC_SET_DISCONNECTED(sock);
+ silc_client_close_connection(client, sock);
+}
+
+/* Received error message from server. Display it on the screen.
+ We don't take any action what so ever of the error message. */
+
+void silc_client_error_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message)
+{
+ char *msg;
+
+ msg = silc_calloc(message->len + 1, sizeof(char));
+ memcpy(msg, message->data, message->len);
+ silc_say(client, msg);
+ silc_free(msg);
+}
+
+/* Received notify message from server */
+
+void silc_client_notify_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message)
+{
+ char *msg;
+
+ msg = silc_calloc(message->len + 1, sizeof(char));
+ memcpy(msg, message->data, message->len);
+ silc_say(client, msg);
+ silc_free(msg);
+}
+
+/* Processes the received new Client ID from server. Old Client ID is
+ deleted from cache and new one is added. */
+
+void silc_client_receive_new_id(SilcClient client,
+ SilcSocketConnection sock,
+ unsigned char *id_string)
+{
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ char *nickname = win->nickname;
+
+#define CIDC(x) win->client_id_cache[(x) - 32]
+#define CIDCC(x) win->client_id_cache_count[(x) - 32]
+
+ /* Delete old ID from ID cache */
+ silc_idcache_del_by_id(CIDC(nickname[0]), CIDCC(nickname[0]),
+ SILC_ID_CLIENT, win->local_id);
+
+ /* Save the new ID */
+ if (win->local_id)
+ silc_free(win->local_id);
+ win->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+ if (win->local_id_data)
+ silc_free(win->local_id_data);
+ win->local_id_data =
+ silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
+ memcpy(win->local_id_data, id_string, SILC_ID_CLIENT_LEN);
+ win->local_id_data_len = SILC_ID_CLIENT_LEN;
+ if (!win->local_entry)
+ win->local_entry = silc_calloc(1, sizeof(*win->local_entry));
+ win->local_entry->nickname = win->nickname;
+ win->local_entry->id = win->local_id;
+
+ /* Put it to the ID cache */
+ CIDCC(nickname[0]) = silc_idcache_add(&CIDC(nickname[0]),
+ CIDCC(nickname[0]),
+ win->nickname, SILC_ID_CLIENT,
+ win->local_id,
+ (void *)win->local_entry);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Processed received Channel ID for a channel. This is called when client
+ joins to channel and server replies with channel ID. The ID is cached. */
+
+void silc_client_new_channel_id(SilcClient client,
+ SilcSocketConnection sock,
+ char *channel_name,
+ unsigned char *id_string)
+{
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ SilcChannelID *id;
+ SilcChannelEntry channel;
+
+ SILC_LOG_DEBUG(("New channel ID"));
+
+#define CIDC(x) win->channel_id_cache[(x) - 32]
+#define CIDCC(x) win->channel_id_cache_count[(x) - 32]
+
+ id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+ channel = silc_calloc(1, sizeof(*channel));
+ channel->channel_name = channel_name;
+ channel->id = id;
+ win->current_channel = channel;
+
+ /* Put it to the ID cache */
+ CIDCC(channel_name[0]) = silc_idcache_add(&CIDC(channel_name[0]),
+ CIDCC(channel_name[0]),
+ channel_name, SILC_ID_CHANNEL,
+ id, (void *)channel);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Processes received key for channel. The received key will be used
+ to protect the traffic on the channel for now on. Client must receive
+ the key to the channel before talking on the channel is possible.
+ This is the key that server has generated, this is not the channel
+ private key, it is entirely local setting. */
+
+void silc_client_receive_channel_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet)
+{
+ int i;
+ unsigned char *id_string, *key, *cipher;
+ unsigned int key_len;
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ SilcChannelID *id;
+ SilcIDCache *id_cache = NULL;
+ SilcChannelEntry channel;
+ SilcChannelKeyPayload payload;
+
+ SILC_LOG_DEBUG(("Received key for channel"));
+
+#define CIDC(x) win->channel_id_cache[(x)]
+#define CIDCC(x) win->channel_id_cache_count[(x)]
+
+ payload = silc_channel_key_parse_payload(packet);
+ if (!payload)
+ return;
+
+ id_string = silc_channel_key_get_id(payload, NULL);
+ if (!id_string) {
+ silc_channel_key_free_payload(payload);
+ return;
+ }
+ id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+
+ /* Find channel. XXX: This is bad and slow. */
+ for (i = 0; i < 96; i++) {
+ if (CIDC(i) == NULL)
+ continue;
+ if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)id,
+ SILC_ID_CHANNEL, &id_cache))
+ break;
+ }
+
+ if (!id_cache)
+ goto out;
+
+ /* Save the key */
+ key = silc_channel_key_get_key(payload, &key_len);
+ cipher = silc_channel_key_get_cipher(payload, NULL);
+
+ channel = (SilcChannelEntry)id_cache->context;
+ channel->key_len = key_len;
+ channel->key = silc_calloc(key_len, sizeof(*channel->key));
+ memcpy(channel->key, key, key_len);
+
+ silc_cipher_alloc(cipher, &channel->channel_key);
+ if (!channel->channel_key) {
+ silc_say(client, "Cannot talk to channel: unsupported cipher %s", cipher);
+ goto out;
+ }
+ channel->channel_key->cipher->set_key(channel->channel_key->context,
+ key, key_len);
+
+ /* Client is now joined to the channel */
+ channel->on_channel = TRUE;
+
+ out:
+ silc_free(id);
+ silc_channel_key_free_payload(payload);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Process received message to a channel (or from a channel, really). This
+ decrypts the channel message with channel specific key and parses the
+ channel payload. Finally it displays the message on the screen. */
+
+void silc_client_channel_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ int i;
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ SilcBuffer buffer = packet->buffer;
+ SilcChannelPayload payload = NULL;
+ SilcChannelID *id = NULL;
+ SilcChannelEntry channel;
+ SilcIDCache *id_cache = NULL;
+
+#define CIDC(x) win->channel_id_cache[(x)]
+#define CIDCC(x) win->channel_id_cache_count[(x)]
+
+ /* Sanity checks */
+ if (packet->dst_id_type != SILC_ID_CHANNEL)
+ goto out;
+
+ id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+
+ /* Find the channel entry from channels on this window */
+ for (i = 0; i < 96; i++) {
+ if (CIDC(i) == NULL)
+ continue;
+ if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)id,
+ SILC_ID_CHANNEL, &id_cache))
+ break;
+ }
+
+ if (!id_cache)
+ goto out;
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Decrypt the channel message payload. Push the IV out of the way,
+ since it is not encrypted (after pushing buffer->tail has the IV). */
+ silc_buffer_push_tail(buffer, 16);
+ channel->channel_key->cipher->decrypt(channel->channel_key->context,
+ buffer->data, buffer->data,
+ buffer->len, buffer->tail);
+ silc_buffer_pull_tail(buffer, 16);
+
+ /* Parse the channel message payload */
+ payload = silc_channel_parse_payload(buffer);
+ if (!payload)
+ goto out;
+
+ /* Display the message on screen */
+ if (packet->src_id_type == SILC_ID_CLIENT)
+ /* Message from client */
+ silc_print(client, "<%s> %s", silc_channel_get_nickname(payload, NULL),
+ silc_channel_get_data(payload, NULL));
+ else
+ /* Message from server */
+ silc_say(client, "%s", silc_channel_get_data(payload, NULL));
+
+ out:
+ if (id)
+ silc_free(id);
+ if (payload)
+ silc_channel_free_payload(payload);
+#undef CIDC
+#undef CIDCC
+}
--- /dev/null
+/*
+
+ client.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+/* Window structure used in client to associate all the important
+ connection (window) specific data to this structure. How the window
+ actually appears on the screen in handeled by the silc_screen*
+ routines in screen.c. */
+typedef struct {
+ /*
+ * Local data
+ */
+ char *nickname;
+
+ /* Local client ID for this connection */
+ SilcClientID *local_id;
+
+ /* Decoded local ID so that the above defined ID would not have
+ to be decoded for every packet. */
+ unsigned char *local_id_data;
+ unsigned int local_id_data_len;
+
+ /* Own client entry. */
+ SilcClientEntry local_entry;
+
+ /*
+ * Remote data
+ */
+ char *remote_host;
+ int remote_port;
+ int remote_type;
+
+ /* Remote client ID for this connection */
+ SilcClientID *remote_id;
+
+ /* Remote local ID so that the above defined ID would not have
+ to be decoded for every packet. */
+ unsigned char *remote_id_data;
+ unsigned int remote_id_data_len;
+
+ /*
+ * Common data
+ */
+ /* Keys */
+ SilcCipher send_key;
+ SilcCipher receive_key;
+ SilcPKCS public_key;
+ SilcHmac hmac;
+ unsigned char *hmac_key;
+ unsigned int hmac_key_len;
+
+ /* Client ID and Channel ID cache. Messages transmitted in SILC network
+ are done using different unique ID's. These are the cache for
+ thoses ID's used in the communication. */
+ SilcIDCache *client_id_cache[96];
+ unsigned int client_id_cache_count[96];
+ SilcIDCache *channel_id_cache[96];
+ unsigned int channel_id_cache_count[96];
+ SilcIDCache *server_id_cache;
+ unsigned int server_id_cache_count;
+
+ /* Current channel on window. All channel's are saved (allocated) into
+ the cache entries. */
+ SilcChannelEntry current_channel;
+
+ /* Socket connection object for this connection (window). This
+ object will have a back-pointer to this window object for fast
+ referencing (sock->user_data). */
+ SilcSocketConnection sock;
+
+ /* The actual physical screen. This data is handled by the
+ screen handling routines. */
+ void *screen;
+} *SilcClientWindow;
+
+typedef struct {
+ char *username;
+ char *realname;
+
+ /* SILC client task queues */
+ SilcTaskQueue io_queue;
+ SilcTaskQueue timeout_queue;
+ SilcTaskQueue generic_queue;
+
+ /* Input buffer that holds the characters user types. This is
+ used only to store the typed chars for a while. */
+ SilcBuffer input_buffer;
+
+ /* Table of windows in client. All the data, including connection
+ specific data, is saved in here. */
+ SilcClientWindow *windows;
+ unsigned int windows_count;
+
+ /* Currently active window. This is pointer to the window table
+ defined above. This must never be free'd directly. */
+ SilcClientWindow current_win;
+
+ /* The SILC client screen object */
+ SilcScreen screen;
+
+ /* Generic cipher and hash objects */
+ SilcCipher none_cipher;
+ SilcHash md5hash;
+ SilcHash sha1hash;
+ SilcHmac md5hmac;
+ SilcHmac sha1hmac;
+
+ /* Configuration object */
+ SilcClientConfig config;
+
+ /* Random Number Generator */
+ SilcRng rng;
+
+#ifdef SILC_SIM
+ /* SIM (SILC Module) table */
+ SilcSimContext **sim;
+ unsigned int sim_count;
+#endif
+} SilcClientObject;
+
+typedef SilcClientObject *SilcClient;
+
+/* Macros */
+
+#ifndef CTRL
+#define CTRL(x) ((x) & 0x1f) /* Ctrl+x */
+#endif
+
+/* Registers generic task for file descriptor for reading from network and
+ writing to network. As being generic task the actual task is allocated
+ only once and after that the same task applies to all registered fd's. */
+#define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd) \
+do { \
+ SilcTask tmptask = silc_task_register(client->generic_queue, (fd), \
+ silc_client_packet_process, \
+ context, 0, 0, \
+ SILC_TASK_GENERIC, \
+ SILC_TASK_PRI_NORMAL); \
+ silc_task_set_iotype(tmptask, SILC_TASK_WRITE); \
+} while(0)
+
+#define SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd) \
+do { \
+ silc_schedule_set_listen_fd((fd), (1L << SILC_TASK_READ)); \
+} while(0) \
+
+#define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(fd) \
+do { \
+ silc_schedule_set_listen_fd((fd), ((1L << SILC_TASK_READ) | \
+ (1L << SILC_TASK_WRITE))); \
+} while(0)
+
+/* Finds socket connection object by file descriptor */
+#define SILC_CLIENT_GET_SOCK(__x, __fd, __sock) \
+do { \
+ int __i; \
+ \
+ for (__i = 0; __i < (__x)->windows_count; __i++) \
+ if ((__x)->windows[__i]->sock->sock == (__fd)) \
+ break; \
+ \
+ if (__i >= (__x)->windows_count) \
+ (__sock) = NULL; \
+ (__sock) = (__x)->windows[__i]->sock; \
+} while(0)
+
+/* Returns TRUE if windows is currently active window */
+#define SILC_CLIENT_IS_CURRENT_WIN(__x, __win) ((__x)->current_win == (__win))
+
+/* Prototypes */
+int silc_client_alloc(SilcClient *new_client);
+void silc_client_free(SilcClient client);
+int silc_client_init(SilcClient client);
+void silc_client_stop(SilcClient client);
+void silc_client_run(SilcClient client);
+void silc_client_parse_command_line(unsigned char *buffer,
+ unsigned char ***parsed,
+ unsigned int **parsed_lens,
+ unsigned int **parsed_types,
+ unsigned int *parsed_num,
+ unsigned int max_args);
+int silc_client_connect_to_server(SilcClient client, int port,
+ char *host);
+void silc_client_packet_send(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_client_packet_send_to_channel(SilcClient client,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_client_packet_send_private_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcClientEntry client_entry,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_client_close_connection(SilcClient client,
+ SilcSocketConnection sock);
+void silc_client_disconnected_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message);
+void silc_client_error_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message);
+void silc_client_notify_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message);
+void silc_client_receive_new_id(SilcClient client,
+ SilcSocketConnection sock,
+ unsigned char *id_string);
+void silc_client_new_channel_id(SilcClient client,
+ SilcSocketConnection sock,
+ char *channel_name,
+ unsigned char *id_string);
+void silc_client_receive_channel_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet);
+void silc_client_channel_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+#endif
--- /dev/null
+/*
+
+ serverconfig.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+#include "clientconfig.h"
+
+/*
+ All possible configuration sections for SILC client.
+*/
+SilcClientConfigSection silc_client_config_sections[] = {
+ { "[cipher]",
+ SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER, 4 },
+ { "[pkcs]",
+ SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS, 2 },
+ { "[hash]",
+ SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION, 4 },
+ { "[connection]",
+ SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
+ { "[commands]",
+ SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND, 0 },
+
+ { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
+};
+
+/* Allocates a new configuration object, opens configuration file and
+ parses the file. The parsed data is returned to the newly allocated
+ configuration object. */
+
+SilcClientConfig silc_client_config_alloc(char *filename)
+{
+ SilcClientConfig new;
+ SilcBuffer buffer;
+ SilcClientConfigParse config_parse;
+
+ SILC_LOG_DEBUG(("Allocating new configuration object"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ fprintf(stderr, "Could not allocate new configuration object");
+ return NULL;
+ }
+
+ new->filename = filename;
+
+ /* Open configuration file and parse it */
+ config_parse = NULL;
+ buffer = NULL;
+ silc_config_open(filename, &buffer);
+ if (!buffer)
+ goto fail;
+ if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
+ goto fail;
+ if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
+ goto fail;
+
+ silc_free(buffer);
+
+ return new;
+
+ fail:
+ silc_free(new);
+ return NULL;
+}
+
+/* Free's a configuration object. */
+
+void silc_client_config_free(SilcClientConfig config)
+{
+ if (config) {
+
+ silc_free(config);
+ }
+}
+
+/* Parses the the buffer and returns the parsed lines into return_config
+ argument. The return_config argument doesn't have to be initialized
+ before calling this. It will be initialized during the parsing. The
+ buffer sent as argument can be safely free'd after this function has
+ succesfully returned. */
+
+int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
+ SilcClientConfigParse *return_config)
+{
+ int i, begin;
+ unsigned int linenum;
+ char line[1024], *cp;
+ SilcClientConfigSection *cptr = NULL;
+ SilcClientConfigParse parse = *return_config, first = NULL;
+
+ SILC_LOG_DEBUG(("Parsing configuration file"));
+
+ begin = 0;
+ linenum = 0;
+ while((begin = silc_gets(line, sizeof(line),
+ buffer->data, buffer->len, begin)) != EOF) {
+ cp = line;
+ linenum++;
+
+ /* Check for bad line */
+ if (silc_check_line(cp))
+ continue;
+
+ /* Remove tabs and whitespaces from the line */
+ if (strchr(cp, '\t')) {
+ i = 0;
+ while(strchr(cp + i, '\t')) {
+ *strchr(cp + i, '\t') = ' ';
+ i++;
+ }
+ }
+ for (i = 0; i < strlen(cp); i++) {
+ if (cp[i] != ' ') {
+ if (i)
+ cp++;
+ break;
+ }
+ cp++;
+ }
+
+ /* Parse line */
+ switch(cp[0]) {
+ case '[':
+ /*
+ * Start of a section
+ */
+
+ /* Remove new line sign */
+ if (strchr(cp, '\n'))
+ *strchr(cp, '\n') = '\0';
+
+ /* Check for matching sections */
+ for (cptr = silc_client_config_sections; cptr->section; cptr++)
+ if (!strcmp(cp, cptr->section))
+ break;
+
+ if (!cptr->section) {
+ fprintf(stderr, "%s:%d: Unknown section `%s'\n",
+ config->filename, linenum, cp);
+ return FALSE;
+ }
+
+ break;
+ default:
+ /*
+ * Start of a configuration line
+ */
+
+ /* Handle config section */
+ if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
+
+ if (strchr(cp, '\n'))
+ *strchr(cp, '\n') = ':';
+
+ if (parse == NULL) {
+ parse = silc_calloc(1, sizeof(*parse));
+ parse->line = NULL;
+ parse->section = NULL;
+ parse->next = NULL;
+ parse->prev = NULL;
+ } else {
+ if (parse->next == NULL) {
+ parse->next = silc_calloc(1, sizeof(*parse->next));
+ parse->next->line = NULL;
+ parse->next->section = NULL;
+ parse->next->next = NULL;
+ parse->next->prev = parse;
+ parse = parse->next;
+ }
+ }
+
+ if (first == NULL)
+ first = parse;
+
+ /* Add the line to parsing structure for further parsing. */
+ if (parse) {
+ parse->section = cptr;
+ parse->line = silc_buffer_alloc(strlen(cp) + 1);
+ parse->linenum = linenum;
+ silc_buffer_pull_tail(parse->line, strlen(cp));
+ silc_buffer_put(parse->line, cp, strlen(cp));
+ }
+ }
+ break;
+ }
+ }
+
+ /* Set the return_config argument to its first value so that further
+ parsing can be started from the first line. */
+ *return_config = first;
+
+ return TRUE;
+}
+
+/* Parses the lines earlier read from configuration file. The config object
+ must not be initialized, it will be initialized in this function. The
+ parse_config argument is uninitialized automatically during this
+ function. */
+
+int silc_client_config_parse_lines(SilcClientConfig config,
+ SilcClientConfigParse parse_config)
+{
+ int ret, check = FALSE;
+ char *tmp;
+ SilcClientConfigParse pc = parse_config;
+ SilcBuffer line;
+
+ SILC_LOG_DEBUG(("Parsing configuration lines"));
+
+ if (!config)
+ return FALSE;
+
+ while(pc) {
+ check = FALSE;
+ line = pc->line;
+
+ /* Get number of tokens in line (command section is handeled
+ specially and has no tokens at all). */
+ ret = silc_config_check_num_token(line);
+ if (ret != pc->section->maxfields &&
+ pc->section->type != SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND) {
+ /* Bad line */
+ fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
+ config->filename, pc->linenum, ret,
+ pc->section->maxfields);
+ break;
+ }
+
+ /* Parse the line */
+ switch(pc->section->type) {
+ case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
+
+ if (!config->cipher) {
+ config->cipher = silc_calloc(1, sizeof(*config->cipher));
+ config->cipher->next = NULL;
+ config->cipher->prev = NULL;
+ } else {
+ if (!config->cipher->next) {
+ config->cipher->next =
+ silc_calloc(1, sizeof(*config->cipher->next));
+ config->cipher->next->next = NULL;
+ config->cipher->next->prev = config->cipher;
+ config->cipher = config->cipher->next;
+ }
+ }
+
+ /* Get cipher name */
+ ret = silc_config_get_token(line, &config->cipher->alg_name);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Cipher name not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+
+ /* Get module name */
+ config->cipher->sim_name = NULL;
+ ret = silc_config_get_token(line, &config->cipher->sim_name);
+ if (ret < 0)
+ break;
+
+ /* Get block length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Cipher block length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->cipher->block_len = atoi(tmp);
+ silc_free(tmp);
+
+ /* Get key length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Cipher key length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->cipher->key_len = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ break;
+
+ case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
+
+ if (!config->pkcs) {
+ config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
+ config->pkcs->next = NULL;
+ config->pkcs->prev = NULL;
+ } else {
+ if (!config->pkcs->next) {
+ config->pkcs->next =
+ silc_calloc(1, sizeof(*config->pkcs->next));
+ config->pkcs->next->next = NULL;
+ config->pkcs->next->prev = config->pkcs;
+ config->pkcs = config->pkcs->next;
+ }
+ }
+
+ /* Get PKCS name */
+ ret = silc_config_get_token(line, &config->pkcs->alg_name);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: PKCS name not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+
+ /* Get key length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: PKCS key length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->pkcs->key_len = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ break;
+
+ case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
+
+ if (!config->hash_func) {
+ config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
+ config->hash_func->next = NULL;
+ config->hash_func->prev = NULL;
+ } else {
+ if (!config->hash_func->next) {
+ config->hash_func->next =
+ silc_calloc(1, sizeof(*config->hash_func->next));
+ config->hash_func->next->next = NULL;
+ config->hash_func->next->prev = config->hash_func;
+ config->hash_func = config->hash_func->next;
+ }
+ }
+
+ /* Get Hash function name */
+ ret = silc_config_get_token(line, &config->hash_func->alg_name);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Hash function name not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+
+ /* Get Hash function module name */
+ config->hash_func->sim_name = NULL;
+ ret = silc_config_get_token(line, &config->hash_func->sim_name);
+ if (ret < 0)
+ break;
+
+ /* Get block length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Hash function block length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->hash_func->block_len = atoi(tmp);
+ silc_free(tmp);
+
+ /* Get hash length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->hash_func->key_len = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ break;
+
+ case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
+
+ if (!config->conns) {
+ config->conns = silc_calloc(1, sizeof(*config->conns));
+ config->conns->next = NULL;
+ config->conns->prev = NULL;
+ } else {
+ if (!config->conns->next) {
+ config->conns->next = silc_calloc(1, sizeof(*config->conns));
+ config->conns->next->next = NULL;
+ config->conns->next->prev = config->conns;
+ config->conns = config->conns->next;
+ }
+ }
+
+ /* Get host */
+ ret = silc_config_get_token(line, &config->conns->host);
+ if (ret < 0)
+ break;
+ if (ret == 0)
+ /* Any host */
+ config->conns->host = strdup("*");
+
+ /* Get authentication method */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
+ strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
+ fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+ config->filename, pc->linenum, tmp);
+ break;
+ }
+
+ if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
+ config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+ if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
+ config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+ silc_free(tmp);
+ }
+
+ /* Get authentication data */
+ ret = silc_config_get_token(line, &config->conns->auth_data);
+ if (ret < 0)
+ break;
+
+ /* Get port */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->conns->port = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ check = TRUE;
+ break;
+
+ case SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND:
+
+ if (!config->commands) {
+ config->commands = silc_calloc(1, sizeof(*config->commands));
+ config->commands->next = NULL;
+ config->commands->prev = NULL;
+ } else {
+ if (!config->commands->next) {
+ config->commands->next = silc_calloc(1, sizeof(*config->commands));
+ config->commands->next->next = NULL;
+ config->commands->next->prev = config->commands;
+ config->commands = config->commands->next;
+ }
+ }
+
+ /* Get command line (this may include parameters as well. They
+ will be parsed later with standard command parser when
+ executing particular command.) */
+ config->commands->command = strdup(line->data);
+ if (ret < 0)
+ break;
+
+ check = TRUE;
+ break;
+
+ case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
+ default:
+ break;
+ }
+
+ /* Check for error */
+ if (check == FALSE) {
+ /* Line could not be parsed */
+ fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
+ break;
+ }
+
+ pc = pc->next;
+ }
+
+ if (check == FALSE)
+ return FALSE;;
+
+ /* Before returning all the lists in the config object must be set
+ to their first values (the last value is first here). */
+ while (config->cipher && config->cipher->prev)
+ config->cipher = config->cipher->prev;
+ while (config->pkcs && config->pkcs->prev)
+ config->pkcs = config->pkcs->prev;
+ while (config->hash_func && config->hash_func->prev)
+ config->hash_func = config->hash_func->prev;
+ while (config->conns && config->conns->prev)
+ config->conns = config->conns->prev;
+ while (config->commands && config->commands->prev)
+ config->commands = config->commands->prev;
+
+ SILC_LOG_DEBUG(("Done"));
+
+ return TRUE;
+}
+
+/* Registers configured ciphers. These can then be allocated by the
+ client when needed. */
+
+void silc_client_config_register_ciphers(SilcClientConfig config)
+{
+ SilcClientConfigSectionAlg *alg;
+ SilcClient client = (SilcClient)config->client;
+
+ SILC_LOG_DEBUG(("Registering configured ciphers"));
+
+ alg = config->cipher;
+ while(alg) {
+
+ if (!alg->sim_name) {
+ /* Crypto module is supposed to be built in. Nothing to be done
+ here except to test that the cipher really is built in. */
+ SilcCipher tmp = NULL;
+
+ if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
+ SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
+ silc_client_stop(client);
+ exit(1);
+ }
+ silc_cipher_free(tmp);
+
+#ifdef SILC_SIM
+ } else {
+ /* Load (try at least) the crypto SIM module */
+ SilcCipherObject cipher;
+ SilcSimContext *sim;
+
+ memset(&cipher, 0, sizeof(cipher));
+ cipher.name = alg->alg_name;
+ cipher.block_len = alg->block_len;
+ cipher.key_len = alg->key_len * 8;
+
+ sim = silc_sim_alloc();
+ sim->type = SILC_SIM_CIPHER;
+ sim->libname = alg->sim_name;
+
+ if ((silc_sim_load(sim))) {
+ cipher.set_key =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_SET_KEY));
+ SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
+ cipher.set_key_with_string =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
+ SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
+ cipher.encrypt =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_ENCRYPT_CBC));
+ SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
+ cipher.decrypt =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_DECRYPT_CBC));
+ SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
+ cipher.context_len =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_CONTEXT_LEN));
+ SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
+
+ /* Put the SIM to the table of all SIM's in client */
+ client->sim = silc_realloc(client->sim,
+ sizeof(*client->sim) *
+ (client->sim_count + 1));
+ client->sim[client->sim_count] = sim;
+ client->sim_count++;
+ } else {
+ SILC_LOG_ERROR(("Error configuring ciphers"));
+ silc_client_stop(client);
+ exit(1);
+ }
+
+ /* Register the cipher */
+ silc_cipher_register(&cipher);
+#endif
+ }
+
+ alg = alg->next;
+ }
+}
+
+/* Registers configured PKCS's. */
+/* XXX: This really doesn't do anything now since we have statically
+ registered our PKCS's. This should be implemented when PKCS works
+ as SIM's. This checks now only that the PKCS user requested is
+ really out there. */
+
+void silc_client_config_register_pkcs(SilcClientConfig config)
+{
+ SilcClientConfigSectionAlg *alg = config->pkcs;
+ SilcClient client = (SilcClient)config->client;
+ SilcPKCS tmp = NULL;
+
+ SILC_LOG_DEBUG(("Registering configured PKCS"));
+
+ while(alg) {
+
+ if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
+ SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
+ silc_client_stop(client);
+ exit(1);
+ }
+ silc_free(tmp);
+
+ alg = alg->next;
+ }
+}
+
+/* Registers configured hash functions. These can then be allocated by the
+ client when needed. */
+
+void silc_client_config_register_hashfuncs(SilcClientConfig config)
+{
+ SilcClientConfigSectionAlg *alg;
+ SilcClient client = (SilcClient)config->client;
+
+ SILC_LOG_DEBUG(("Registering configured hash functions"));
+
+ alg = config->hash_func;
+ while(alg) {
+
+ if (!alg->sim_name) {
+ /* Hash module is supposed to be built in. Nothing to be done
+ here except to test that the hash function really is built in. */
+ SilcHash tmp = NULL;
+
+ if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
+ SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
+ silc_client_stop(client);
+ exit(1);
+ }
+ silc_free(tmp);
+
+#ifdef SILC_SIM
+ } else {
+ /* Load (try at least) the hash SIM module */
+ SilcHashObject hash;
+ SilcSimContext *sim;
+
+ memset(&hash, 0, sizeof(hash));
+ hash.name = alg->alg_name;
+ hash.block_len = alg->block_len;
+ hash.hash_len = alg->key_len;
+
+ sim = silc_sim_alloc();
+ sim->type = SILC_SIM_HASH;
+ sim->libname = alg->sim_name;
+
+ if ((silc_sim_load(sim))) {
+ hash.init =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_INIT));
+ SILC_LOG_DEBUG(("init=%p", hash.init));
+ hash.update =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_UPDATE));
+ SILC_LOG_DEBUG(("update=%p", hash.update));
+ hash.final =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_FINAL));
+ SILC_LOG_DEBUG(("final=%p", hash.final));
+ hash.context_len =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_CONTEXT_LEN));
+ SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
+
+ /* Put the SIM to the table of all SIM's in client */
+ client->sim = silc_realloc(client->sim,
+ sizeof(*client->sim) *
+ (client->sim_count + 1));
+ client->sim[client->sim_count] = sim;
+ client->sim_count++;
+ } else {
+ SILC_LOG_ERROR(("Error configuring hash functions"));
+ silc_client_stop(client);
+ exit(1);
+ }
+
+ /* Register the cipher */
+ silc_hash_register(&hash);
+#endif
+ }
+
+ alg = alg->next;
+ }
+}
+
+
+SilcClientConfigSectionConnection *
+silc_client_config_find_connection(SilcClientConfig config,
+ char *host, int port)
+{
+ int i;
+ SilcClientConfigSectionConnection *conn = NULL;
+
+ SILC_LOG_DEBUG(("Finding connection"));
+
+ if (!host)
+ return NULL;
+
+ if (!config->conns)
+ return NULL;
+
+ conn = config->conns;
+ for (i = 0; conn; i++) {
+ if (silc_string_compare(conn->host, host))
+ break;
+ conn = conn->next;
+ }
+
+ if (!conn)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Found match"));
+
+ return conn;
+}
--- /dev/null
+/*
+
+ clientconfig.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENTCONFIG_H
+#define CLIENTCONFIG_H
+
+/* Holds information of configured algorithms */
+typedef struct SilcClientConfigSectionAlgStruct {
+ char *alg_name;
+ char *sim_name;
+ unsigned int block_len;
+ unsigned int key_len;
+ struct SilcClientConfigSectionAlgStruct *next;
+ struct SilcClientConfigSectionAlgStruct *prev;
+#define SILC_CLIENT_CONFIG_MODNAME "builtin"
+} SilcClientConfigSectionAlg;
+
+/* Holds all server connections from config file */
+typedef struct SilcClientConfigSectionConnectionStruct {
+ char *host;
+ int auth_meth;
+ char *auth_data;
+ unsigned short port;
+ struct SilcClientConfigSectionConnectionStruct *next;
+ struct SilcClientConfigSectionConnectionStruct *prev;
+#define SILC_CLIENT_CONFIG_AUTH_METH_PASSWD "passwd"
+#define SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY "pubkey"
+} SilcClientConfigSectionConnection;
+
+/* Holds all given commands from config file */
+typedef struct SilcClientConfigSectionCommandStruct {
+ char *command;
+ struct SilcClientConfigSectionCommandStruct *next;
+ struct SilcClientConfigSectionCommandStruct *prev;
+} SilcClientConfigSectionCommand;
+
+/*
+ SILC Client Config object.
+
+ This object holds all the data parsed from the SILC client configuration
+ file. This is mainly used at the initialization of the client.
+
+*/
+typedef struct {
+ /* Pointer back to the client */
+ void *client;
+
+ /* Filename of the configuration file */
+ char *filename;
+
+ /* Configuration sections */
+ SilcClientConfigSectionAlg *cipher;
+ SilcClientConfigSectionAlg *pkcs;
+ SilcClientConfigSectionAlg *hash_func;
+ SilcClientConfigSectionConnection *conns;
+ SilcClientConfigSectionCommand *commands;
+} SilcClientConfigObject;
+
+typedef SilcClientConfigObject *SilcClientConfig;
+
+/* Configuration section type enumerations. */
+typedef enum {
+ SILC_CLIENT_CONFIG_SECTION_TYPE_NONE = 0,
+ SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER,
+ SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS,
+ SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION,
+ SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION,
+ SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND = 253, /* Special section */
+} SilcClientConfigSectionType;
+
+/* SILC Configuration Section structure. */
+typedef struct {
+ const char *section;
+ SilcClientConfigSectionType type;
+ unsigned int maxfields;
+} SilcClientConfigSection;
+
+/* List of all possible config sections in SILC client */
+extern SilcClientConfigSection silc_client_config_sections[];
+
+/* Structure used in parsing the configuration lines. The line is read
+ from a file to this structure before parsing it further. */
+typedef struct SilcClientConfigParseStruct {
+ SilcBuffer line;
+ unsigned int linenum;
+ SilcClientConfigSection *section;
+ struct SilcClientConfigParseStruct *next;
+ struct SilcClientConfigParseStruct *prev;
+} *SilcClientConfigParse;
+
+/* Prototypes */
+SilcClientConfig silc_client_config_alloc(char *filename);
+void silc_client_config_free(SilcClientConfig config);
+int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
+ SilcClientConfigParse *return_config);
+int silc_client_config_parse_lines(SilcClientConfig config,
+ SilcClientConfigParse parse_config);
+int silc_client_config_check_sections(unsigned int checkmask);
+void silc_client_config_setlogfiles(SilcClientConfig config);
+void silc_client_config_register_ciphers(SilcClientConfig config);
+void silc_client_config_register_pkcs(SilcClientConfig config);
+void silc_client_config_register_hashfuncs(SilcClientConfig config);
+SilcClientConfigSectionConnection *
+silc_client_config_find_connection(SilcClientConfig config,
+ char *host, int port);
+
+#endif
--- /dev/null
+/*
+
+ client.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Internal routine used to print lines to window. This can split the
+ line neatly if a word would overlap the line. */
+
+static void silc_print_to_window(WINDOW *win, char *message)
+{
+ int str_len, len;
+
+ str_len = strlen(message);
+
+ if (str_len > COLS - 1) {
+ /* Split overlapping words to next line */
+ /* XXX In principal this is wrong as this modifies the original
+ string as it replaces the last ' ' with '\n'. This could be done
+ with little more work so that it would not replace anything. */
+ len = COLS - 1;
+ while (1) {
+
+ while (len && message[len] != ' ')
+ len--;
+
+ if (!len)
+ break;
+
+ message[len] = '\n';
+ len += COLS - 1;
+ if (len > str_len)
+ break;
+ }
+ }
+
+ wprintw(win, "%s", message);
+ wrefresh(win);
+}
+
+/* Prints a message with three star (*) sign before the actual message
+ on the current output window. This is used to print command outputs
+ and error messages. */
+/* XXX Change to accept SilcClientWindow and use output window
+ from there (the pointer to the output window must be added to the
+ SilcClientWindow object. */
+
+void silc_say(SilcClient client, char *msg, ...)
+{
+ va_list vp;
+ char message[1024];
+
+ memset(message, 0, sizeof(message));
+ strncat(message, "\n*** ", 5);
+
+ va_start(vp, msg);
+ vsprintf(message + 5, msg, vp);
+ va_end(vp);
+
+ /* Print the message */
+ silc_print_to_window(client->screen->output_win[0], message);
+}
+
+/* Prints message to the screen. This is used to print the messages
+ user is typed and message that came on channels. */
+
+void silc_print(SilcClient client, char *msg, ...)
+{
+ va_list vp;
+ char message[1024];
+
+ memset(message, 0, sizeof(message));
+ strncat(message, "\n ", 2);
+
+ va_start(vp, msg);
+ vsprintf(message + 1, msg, vp);
+ va_end(vp);
+
+ /* Print the message */
+ silc_print_to_window(client->screen->output_win[0], message);
+}
+
+/* Returns user's mail path */
+
+char *silc_get_mail_path()
+{
+ char pathbuf[MAXPATHLEN];
+ char *path;
+
+ if ((path = (char *)getenv("MAIL")) != 0) {
+ strncpy(pathbuf, path, strlen(path));
+ } else {
+ strcpy(pathbuf, _PATH_MAILDIR);
+ strcat(pathbuf, "/");
+ strcat(pathbuf, silc_get_username());
+ }
+
+ return strdup(pathbuf);
+}
+
+/* gets the number of the user's mails, if possible */
+
+int silc_get_number_of_emails()
+{
+ FILE *tl;
+ int num = 0;
+ char *filename;
+ char data[1024];
+
+ filename = silc_get_mail_path();
+
+ tl = fopen(filename, "r");
+ if (!tl) {
+ fprintf(stderr, "Couldn't open mail file (%s).\n", filename);
+ } else {
+ while((fscanf(tl, "%s", data)) != EOF) {
+ if(!strcmp(data, "Subject:"))
+ num++;
+ }
+
+ fclose(tl);
+ }
+
+ return num;
+}
+
+/* Returns the username of the user. If the global variable LOGNAME
+ does not exists we will get the name from the password file. */
+
+char *silc_get_username()
+{
+ char *logname = NULL;
+
+ logname = strdup(getenv("LOGNAME"));
+ if (!logname) {
+ logname = getlogin();
+ if (!logname) {
+ struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if (!pw) {
+ fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ logname = strdup(pw->pw_name);
+ }
+ }
+
+ return logname;
+}
+
+/* Returns the real name of ther user. */
+
+char *silc_get_real_name()
+{
+ char *realname = NULL;
+ struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if (!pw) {
+ fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ if (strchr(pw->pw_gecos, ','))
+ *strchr(pw->pw_gecos, ',') = 0;
+
+ realname = strdup(pw->pw_gecos);
+
+ return realname;
+}
+
+/* Returns time til next minute changes. Used to update the clock when
+ needed. */
+
+int silc_client_time_til_next_min()
+{
+ time_t curtime;
+ struct tm *min;
+
+ curtime = time(0);
+ min = localtime(&curtime);
+
+ return 60 - min->tm_sec;
+}
+
+/* Asks passphrase from user on the input line. */
+
+char *silc_client_ask_passphrase(SilcClient client)
+{
+ char pass1[256], pass2[256];
+ char *ret;
+ int try = 3;
+
+ while(try) {
+
+ /* Print prompt */
+ wattroff(client->screen->input_win, A_INVIS);
+ silc_screen_input_print_prompt(client->screen, "Passphrase: ");
+ wattron(client->screen->input_win, A_INVIS);
+
+ /* Get string */
+ memset(pass1, 0, sizeof(pass1));
+ wgetnstr(client->screen->input_win, pass1, sizeof(pass1));
+
+ /* Print retype prompt */
+ wattroff(client->screen->input_win, A_INVIS);
+ silc_screen_input_print_prompt(client->screen, "Retype passphrase: ");
+ wattron(client->screen->input_win, A_INVIS);
+
+ /* Get string */
+ memset(pass2, 0, sizeof(pass2));
+ wgetnstr(client->screen->input_win, pass2, sizeof(pass2));
+
+ if (!strncmp(pass1, pass2, strlen(pass2)))
+ break;
+
+ try--;
+ }
+
+ ret = silc_calloc(strlen(pass1), sizeof(char));
+ memcpy(ret, pass1, strlen(pass1));
+
+ memset(pass1, 0, sizeof(pass1));
+ memset(pass2, 0, sizeof(pass2));
+
+ wattroff(client->screen->input_win, A_INVIS);
+ silc_screen_input_reset(client->screen);
+
+ return ret;
+}
+
+/* Lists supported (builtin) ciphers */
+
+void silc_client_list_ciphers()
+{
+
+}
+
+/* Lists supported (builtin) hash functions */
+
+void silc_client_list_hash_funcs()
+{
+
+}
+
+/* Lists supported PKCS algorithms */
+
+void silc_client_list_pkcs()
+{
+
+}
+
+/* Displays input prompt on command line and takes input data from user */
+
+char *silc_client_get_input(const char *prompt)
+{
+ char input[2048];
+ int fd;
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "silc: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ memset(input, 0, sizeof(input));
+
+ printf("%s", prompt);
+ fflush(stdout);
+
+ if ((read(fd, input, sizeof(input))) < 0) {
+ fprintf(stderr, "silc: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (strlen(input) <= 1)
+ return NULL;
+
+ if (strchr(input, '\n'))
+ *strchr(input, '\n') = '\0';
+
+ return strdup(input);
+}
+
+/* Displays prompt on command line and takes passphrase with echo
+ off from user. */
+
+char *silc_client_get_passphrase(const char *prompt)
+{
+#if 0
+ char input[2048];
+ char *ret;
+ int fd;
+ struct termios to;
+ struct termios to_old;
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "silc: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ signal(SIGINT, SIG_IGN);
+
+ /* Get terminal info */
+ tcgetattr(fd, &to);
+ to_old = to;
+
+ /* Echo OFF */
+ to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ tcsetattr(fd, TCSANOW, &to);
+
+ memset(input, 0, sizeof(input));
+
+ printf("%s", prompt);
+ fflush(stdout);
+
+ if ((read(fd, input, sizeof(input))) < 0) {
+ fprintf(stderr, "silc: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (strlen(input) <= 1) {
+ tcsetattr(fd, TCSANOW, &to_old);
+ return NULL;
+ }
+
+ if (strchr(input, '\n'))
+ *strchr(input, '\n') = '\0';
+
+ /* Restore old terminfo */
+ tcsetattr(fd, TCSANOW, &to_old);
+ signal(SIGINT, SIG_DFL);
+
+ ret = silc_calloc(strlen(input), sizeof(char));
+ memcpy(ret, input, strlen(input));
+ memset(input, 0, sizeof(input));
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/* Creates new public key and private key pair. This is used only
+ when user wants to create new key pair from command line. */
+
+void silc_client_create_key_pair(char *pkcs_name, int bits)
+{
+ SilcPKCS pkcs;
+ SilcRng rng;
+ unsigned char *key;
+ unsigned int key_len;
+ char *pkfile = NULL, *prvfile = NULL;
+
+ printf("\
+New pair of keys will be created. Please, answer to following questions.\n\
+");
+
+ if (!pkcs_name) {
+ again_name:
+ pkcs_name =
+ silc_client_get_input("PKCS name (l to list names) [rsa]: ");
+ if (!pkcs_name)
+ pkcs_name = strdup("rsa");
+
+ if (*pkcs_name == 'l' || *pkcs_name == 'L') {
+ silc_client_list_pkcs();
+ silc_free(pkcs_name);
+ goto again_name;
+ }
+ }
+
+ if (!bits) {
+ char *length = NULL;
+ length =
+ silc_client_get_input("Key length in bits [1024]: ");
+ if (!length)
+ bits = 1024;
+ else
+ bits = atoi(length);
+ }
+
+ rng = silc_rng_alloc();
+ silc_rng_init(rng);
+ silc_math_primegen_init();
+
+ again_pk:
+ pkfile = silc_client_get_input("Public key filename: ");
+ if (!pkfile) {
+ printf("Public key filename must be defined\n");
+ goto again_pk;
+ }
+
+ again_prv:
+ prvfile = silc_client_get_input("Private key filename: ");
+ if (!prvfile) {
+ printf("Private key filename must be defined\n");
+ goto again_prv;
+ }
+
+ /* Generate keys */
+ silc_pkcs_alloc(pkcs_name, &pkcs);
+ pkcs->pkcs->init(pkcs->context, bits, rng);
+
+ /* Save keys into file */
+ key = silc_pkcs_get_public_key(pkcs, &key_len);
+ silc_pkcs_save_public_key(pkcs, pkfile, key, key_len);
+ memset(key, 0, sizeof(key_len));
+ silc_free(key);
+ key = silc_pkcs_get_private_key(pkcs, &key_len);
+ silc_pkcs_save_private_key(pkcs, prvfile, key, key_len, "");
+ memset(key, 0, sizeof(key_len));
+ silc_free(key);
+
+ silc_math_primegen_uninit();
+ silc_rng_free(rng);
+ silc_pkcs_free(pkcs);
+}
--- /dev/null
+/*
+
+ client.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENTUTIL_H
+#define CLIENTUTIL_H
+
+/* Prototypes */
+void silc_say(SilcClient client, char *msg, ...);
+void silc_print(SilcClient client, char *msg, ...);
+char *silc_get_mail_path();
+int silc_get_number_of_emails();
+char *silc_get_username();
+char *silc_get_real_name();
+int silc_client_time_til_next_min();
+char *silc_client_ask_passphrase(SilcClient client);
+char *silc_client_get_input(const char *prompt);
+char *silc_client_get_passphrase(const char *prompt);
+void silc_client_list_ciphers();
+void silc_client_list_hash_funcs();
+void silc_client_list_pkcs();
+void silc_client_create_key_pair(char *pkcs_name, int bits);
+
+#endif
--- /dev/null
+/*
+
+ command.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Client command list. */
+SilcClientCommand silc_command_list[] =
+{
+ SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
+ SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
+ SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
+ SILC_CF_LAG | SILC_CF_REG, 3),
+ SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
+ SILC_CLIENT_CMD(kill, KILL, "KILL",
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+ SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+ SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(oper, OPER, "OPER",
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+ SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(restart, RESTART, "RESTART",
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+ SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+ SILC_CLIENT_CMD(die, DIE, "DIE",
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+ SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
+ SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
+
+ /*
+ * Local. client specific commands
+ */
+ SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
+ SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
+ SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
+ SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
+ SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
+ SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
+
+ { NULL, 0, NULL, 0},
+};
+
+/* List of pending commands. */
+SilcClientCommandPending *silc_command_pending = NULL;
+
+/* Add new pending command to the list of pending commands. Currently
+ pending commands are executed from command replies, thus we can
+ execute any command after receiving some specific command reply.
+
+ The argument `reply_cmd' is the command reply from where the callback
+ function is to be called, thus, it IS NOT the command to be executed.
+
+ XXX: If needed in the future this support may be extended for
+ commands as well, when any command could be executed after executing
+ some specific command. */
+
+void silc_client_command_pending(SilcCommand reply_cmd,
+ SilcClientCommandCallback callback,
+ void *context)
+{
+ SilcClientCommandPending *reply, *r;
+
+ reply = silc_calloc(1, sizeof(*reply));
+ reply->reply_cmd = reply_cmd;
+ reply->context = context;
+ reply->callback = callback;
+
+ if (silc_command_pending == NULL) {
+ silc_command_pending = reply;
+ return;
+ }
+
+ for (r = silc_command_pending; r; r = r->next) {
+ if (r->next == NULL) {
+ r->next = reply;
+ break;
+ }
+ }
+}
+
+/* Deletes pending command by reply command type. */
+
+void silc_client_command_pending_del(SilcCommand reply_cmd)
+{
+ SilcClientCommandPending *r, *tmp;
+
+ if (silc_command_pending) {
+ if (silc_command_pending->reply_cmd == reply_cmd) {
+ silc_free(silc_command_pending);
+ silc_command_pending = NULL;
+ return;
+ }
+
+ for (r = silc_command_pending; r; r = r->next) {
+ if (r->next && r->next->reply_cmd == reply_cmd) {
+ tmp = r->next;
+ r->next = r->next->next;
+ silc_free(tmp);
+ break;
+ }
+ }
+ }
+}
+
+/* Free command context and its internals */
+
+static void silc_client_command_free(SilcClientCommandContext cmd)
+{
+ int i;
+
+ if (cmd) {
+ for (i = 0; i < cmd->argc; i++)
+ silc_free(cmd->argv[i]);
+ silc_free(cmd);
+ }
+}
+
+/* Command WHOIS. This command is used to query information about
+ specific user. */
+
+SILC_CLIENT_CMD_FUNC(whois)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcBuffer buffer;
+
+ if (cmd->argc < 2 || cmd->argc > 3) {
+ silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
+ goto out;
+ }
+
+ if (!cmd->client->current_win->sock) {
+ silc_say(cmd->client,
+ "You are not connected to a server, use /SERVER to connect");
+ goto out;
+ }
+
+ buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
+ cmd->argc - 1, ++cmd->argv,
+ ++cmd->argv_lens, ++cmd->argv_types);
+ silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ cmd->argv--;
+ cmd->argv_lens--;
+ cmd->argv_types--;
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(whowas)
+{
+}
+
+/* Command IDENTIFY. This command is used to query information about
+ specific user, especially ID's. */
+
+SILC_CLIENT_CMD_FUNC(identify)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcBuffer buffer;
+
+ if (cmd->argc < 2 || cmd->argc > 3) {
+ silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
+ goto out;
+ }
+
+ if (!cmd->client->current_win->sock) {
+ silc_say(cmd->client,
+ "You are not connected to a server, use /SERVER to connect");
+ goto out;
+ }
+
+ buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
+ cmd->argc - 1, ++cmd->argv,
+ ++cmd->argv_lens, ++cmd->argv_types);
+ silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ cmd->argv--;
+ cmd->argv_lens--;
+ cmd->argv_types--;
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+/* Command NICK. Shows current nickname/sets new nickname on current
+ window. */
+
+SILC_CLIENT_CMD_FUNC(nick)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientWindow win = NULL;
+ SilcBuffer buffer;
+
+ if (!cmd->sock) {
+ silc_say(cmd->client,
+ "You are not connected to a server, use /SERVER to connect");
+ goto out;
+ }
+
+ /* Show current nickname */
+ if (cmd->argc < 2) {
+ if (cmd->sock) {
+ silc_say(cmd->client, "Your nickname is %s on server %s",
+ win->nickname, win->remote_host);
+ } else {
+ silc_say(cmd->client, "Your nickname is %s", win->nickname);
+ }
+ goto out;
+ }
+
+ win = (SilcClientWindow)cmd->sock->user_data;
+
+ /* Set new nickname */
+ buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
+ cmd->argc - 1, ++cmd->argv,
+ ++cmd->argv_lens, ++cmd->argv_types);
+ silc_client_packet_send(cmd->client, cmd->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ cmd->argv--;
+ cmd->argv_lens--;
+ cmd->argv_types--;
+ if (win->nickname)
+ silc_free(win->nickname);
+ win->nickname = strdup(cmd->argv[1]);
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+/* Command SERVER. Connects to remote SILC server. This is local command. */
+
+SILC_CLIENT_CMD_FUNC(server)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ int len, port;
+ char *hostname;
+
+ if (cmd->argc < 2) {
+ /* Show current servers */
+ if (!cmd->client->current_win->sock) {
+ silc_say(cmd->client, "You are not connected to any server");
+ silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
+ goto out;
+ }
+
+ goto out;
+ }
+
+ /* See if port is included and then extract it */
+ if (strchr(cmd->argv[1], ':')) {
+ len = strcspn(cmd->argv[1], ":");
+ hostname = silc_calloc(len + 1, sizeof(char));
+ memcpy(hostname, cmd->argv[1], len);
+ port = atoi(cmd->argv[1] + 1 + len);
+ } else {
+ hostname = cmd->argv[1];
+ /* XXX */
+ port = 334;
+ }
+
+ /* Connect asynchronously to not to block user interface */
+ silc_client_connect_to_server(cmd->client, port, hostname);
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(list)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(topic)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(invite)
+{
+}
+
+/* Command QUIT. Closes connection with current server. */
+
+SILC_CLIENT_CMD_FUNC(quit)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcBuffer buffer;
+
+ if (!cmd->client->current_win->sock) {
+ silc_say(cmd->client,
+ "You are not connected to a server, use /SERVER to connect");
+ goto out;
+ }
+
+ buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
+ ++cmd->argv, ++cmd->argv_lens,
+ ++cmd->argv_types);
+ silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ cmd->argv--;
+ cmd->argv_lens--;
+ cmd->argv_types--;
+
+ /* Close connection */
+ silc_client_close_connection(cmd->client, cmd->sock);
+ cmd->client->screen->bottom_line->connection = NULL;
+ silc_screen_print_bottom_line(cmd->client->screen, 0);
+
+ silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(kill)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(info)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(connect)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(ping)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(oper)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(trace)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(notice)
+{
+}
+
+/* Command JOIN. Joins to a channel. */
+
+SILC_CLIENT_CMD_FUNC(join)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientWindow win = NULL;
+ SilcIDCache *id_cache = NULL;
+ SilcBuffer buffer;
+
+#define CIDC(x) win->channel_id_cache[(x) - 32]
+#define CIDCC(x) win->channel_id_cache_count[(x) - 32]
+
+ if (cmd->argc < 2) {
+ /* Show channels currently joined to */
+ if (!cmd->client->current_win->sock) {
+ silc_say(cmd->client, "No current channel for this window");
+ silc_say(cmd->client,
+ "You are not connected to a server, use /SERVER to connect");
+ goto out;
+
+ }
+
+ goto out;
+ }
+
+ if (!cmd->client->current_win->sock) {
+ silc_say(cmd->client,
+ "You are not connected to a server, use /SERVER to connect");
+ goto out;
+ }
+
+ win = (SilcClientWindow)cmd->sock->user_data;
+
+ /* See if we have joined to the requested channel already */
+ silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]),
+ cmd->argv[1], &id_cache);
+
+ if (id_cache) {
+ silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
+ win->current_channel = (SilcChannelEntry)id_cache->context;
+ cmd->client->screen->bottom_line->channel = cmd->argv[1];
+ silc_screen_print_bottom_line(cmd->client->screen, 0);
+ goto out;
+ }
+
+ /* Send JOIN command to the server */
+ buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
+ cmd->argc - 1, ++cmd->argv,
+ ++cmd->argv_lens, ++cmd->argv_types);
+ silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ cmd->argv--;
+ cmd->argv_lens--;
+ cmd->argv_types--;
+
+ out:
+ silc_client_command_free(cmd);
+#undef CIDC
+#undef CIDCC
+}
+
+SILC_CLIENT_CMD_FUNC(motd)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(umode)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(cmode)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(kick)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(restart)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(close)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(die)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(silcoper)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(leave)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(names)
+{
+}
+
+/*
+ * Local commands
+ */
+
+/* HELP command. This is local command and shows help on SILC */
+
+SILC_CLIENT_CMD_FUNC(help)
+{
+
+}
+
+/* CLEAR command. This is local command and clears current output window */
+
+SILC_CLIENT_CMD_FUNC(clear)
+{
+ SilcClient client = (SilcClient)context;
+
+ assert(client->current_win != NULL);
+ wclear((WINDOW *)client->current_win->screen);
+ wrefresh((WINDOW *)client->current_win->screen);
+}
+
+/* VERSION command. This is local command and shows version of the client */
+
+SILC_CLIENT_CMD_FUNC(version)
+{
+
+}
+
+/* Command MSG. Sends private message to user or list of users. */
+/* XXX supports only one destination */
+
+SILC_CLIENT_CMD_FUNC(msg)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientWindow win = NULL;
+ SilcClient client = cmd->client;
+ SilcBuffer buffer;
+ SilcIDCache *id_cache;
+ unsigned int nick_len;
+
+ if (cmd->argc < 3) {
+ silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
+ goto out;
+ }
+
+ if (!cmd->client->current_win->sock) {
+ silc_say(cmd->client,
+ "You are not connected to a server, use /SERVER to connect");
+ goto out;
+ }
+
+ win = (SilcClientWindow)cmd->sock->user_data;
+
+#define CIDC(x) win->client_id_cache[(x) - 32], \
+ win->client_id_cache_count[(x) - 32]
+
+ /* Find ID from cache */
+ if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
+ &id_cache) == FALSE) {
+ SilcClientCommandContext ctx;
+ char ident[512];
+
+ SILC_LOG_DEBUG(("Requesting Client ID from server"));
+
+ /* No ID found. Do query from the server. The query is done by
+ sending simple IDENTIFY command to the server. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->sock = cmd->sock;
+ memset(ident, 0, sizeof(ident));
+ snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
+ silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
+ &ctx->argv_types, &ctx->argc, 2);
+ silc_client_command_identify(ctx);
+
+ /* Mark this command to be pending command and to be executed after
+ we have received the IDENTIFY reply from server. */
+ silc_client_command_pending(SILC_COMMAND_IDENTIFY,
+ silc_client_command_msg, context);
+ return;
+ }
+
+ /* Display the message for our eyes. */
+ silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
+
+ /* Send the private message */
+ silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
+ cmd->argv[2], cmd->argv_lens[2],
+ TRUE);
+ out:
+ silc_client_command_free(cmd);
+#undef CIDC
+}
+
+SILC_CLIENT_CMD_FUNC(away)
+{
+}
--- /dev/null
+/*
+
+ command.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+/*
+ Structure holding one command and pointer to its function.
+
+ SilcCommandCb cb
+
+ Callback function called when this command is executed.
+
+ SilcCommand cmd
+
+ The actual command. These are defined in silccore/silccommand.h
+
+ char *name
+
+ Logical name of the command. This is the visible command name
+ that user uses when calling command. Eg. NICK.
+
+ SilcCommandFlag flags
+
+ Flags for the command. These set how command behaves on different
+ situations. Server sets these flags as well, but to be sure
+ that our client never sends wrong commands we preserve the
+ flags on client side as well.
+
+ XXX: We preserve these so that we define them but currently we
+ don't check the flags at all.
+
+*/
+typedef struct {
+ SilcCommandCb cb;
+ SilcCommand cmd;
+ char *name;
+ SilcCommandFlag flags;
+ unsigned int max_args;
+} SilcClientCommand;
+
+/* All client commands */
+extern SilcClientCommand silc_command_list[];
+
+/* Client command callback function. This included into Command Context,
+ and if it is defined it will be executed when executing the command. */
+typedef void (*SilcClientCommandCallback)(void *context);
+
+/* Context sent as argument to all commands */
+typedef struct {
+ SilcClient client;
+ SilcSocketConnection sock;
+ unsigned int argc;
+ unsigned char **argv;
+ unsigned int *argv_lens;
+ unsigned int *argv_types;
+} *SilcClientCommandContext;
+
+/* Structure holding pending commands. If command is pending it will be
+ executed after command reply has been executed. */
+/* XXX This support may added for commands as well and not just command
+ replies, if needed later. */
+typedef struct SilcClientCommandPendingStruct {
+ SilcCommand reply_cmd;
+ void *context;
+ SilcClientCommandCallback callback;
+
+ struct SilcClientCommandPendingStruct *next;
+} SilcClientCommandPending;
+
+/* List of pending commands */
+extern SilcClientCommandPending *silc_command_pending;
+
+/* Macros */
+
+/* Macro used for command declaration in command list structure */
+#define SILC_CLIENT_CMD(func, cmd, name, flags, args) \
+{ silc_client_command_##func, SILC_COMMAND_##cmd, name, flags, args }
+
+/* Macro used to declare command functions */
+#define SILC_CLIENT_CMD_FUNC(func) \
+void silc_client_command_##func(void *context)
+
+/* Checks for pending commands */
+#define SILC_CLIENT_COMMAND_CHECK_PENDING(ctx) \
+do { \
+ if (silc_command_pending) { \
+ SilcClientCommandPending *r; \
+ SilcCommand cmd; \
+ \
+ cmd = silc_command_get(payload); \
+ for (r = silc_command_pending; r; r = r->next) { \
+ if (r->reply_cmd == cmd) { \
+ ctx->context = r->context; \
+ ctx->callback = r->callback; \
+ break; \
+ } \
+ } \
+ } \
+} while(0)
+
+/* Executed pending command */
+#define SILC_CLIENT_COMMAND_EXEC_PENDING(ctx, cmd) \
+do { \
+ if (ctx->callback) { \
+ (*ctx->callback)(ctx->context); \
+ silc_client_command_pending_del((cmd)); \
+ } \
+} while(0)
+
+/* Prototypes */
+void silc_client_command_pending(SilcCommand reply_cmd,
+ SilcClientCommandCallback callback,
+ void *context);
+void silc_client_command_pending_del(SilcCommand reply_cmd);
+SILC_CLIENT_CMD_FUNC(whois);
+SILC_CLIENT_CMD_FUNC(whowas);
+SILC_CLIENT_CMD_FUNC(identify);
+SILC_CLIENT_CMD_FUNC(nick);
+SILC_CLIENT_CMD_FUNC(server);
+SILC_CLIENT_CMD_FUNC(list);
+SILC_CLIENT_CMD_FUNC(topic);
+SILC_CLIENT_CMD_FUNC(invite);
+SILC_CLIENT_CMD_FUNC(quit);
+SILC_CLIENT_CMD_FUNC(kill);
+SILC_CLIENT_CMD_FUNC(info);
+SILC_CLIENT_CMD_FUNC(connect);
+SILC_CLIENT_CMD_FUNC(ping);
+SILC_CLIENT_CMD_FUNC(oper);
+SILC_CLIENT_CMD_FUNC(join);
+SILC_CLIENT_CMD_FUNC(motd);
+SILC_CLIENT_CMD_FUNC(umode);
+SILC_CLIENT_CMD_FUNC(cmode);
+SILC_CLIENT_CMD_FUNC(kick);
+SILC_CLIENT_CMD_FUNC(restart);
+SILC_CLIENT_CMD_FUNC(close);
+SILC_CLIENT_CMD_FUNC(die);
+SILC_CLIENT_CMD_FUNC(silcoper);
+SILC_CLIENT_CMD_FUNC(leave);
+SILC_CLIENT_CMD_FUNC(names);
+SILC_CLIENT_CMD_FUNC(help);
+SILC_CLIENT_CMD_FUNC(clear);
+SILC_CLIENT_CMD_FUNC(version);
+SILC_CLIENT_CMD_FUNC(msg);
+SILC_CLIENT_CMD_FUNC(away);
+
+#endif
--- /dev/null
+/*
+
+ command_reply.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Command reply functions are "the otherside" of the command functions.
+ * Reply to a command sent by server is handled by these functions.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Client command reply list. */
+SilcClientCommandReply silc_command_reply_list[] =
+{
+ SILC_CLIENT_CMD_REPLY(whois, WHOIS),
+ SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
+ SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
+ SILC_CLIENT_CMD_REPLY(nick, NICK),
+ SILC_CLIENT_CMD_REPLY(list, LIST),
+ SILC_CLIENT_CMD_REPLY(topic, TOPIC),
+ SILC_CLIENT_CMD_REPLY(invite, INVITE),
+ SILC_CLIENT_CMD_REPLY(quit, QUIT),
+ SILC_CLIENT_CMD_REPLY(kill, KILL),
+ SILC_CLIENT_CMD_REPLY(info, INFO),
+ SILC_CLIENT_CMD_REPLY(away, AWAY),
+ SILC_CLIENT_CMD_REPLY(connect, CONNECT),
+ SILC_CLIENT_CMD_REPLY(ping, PING),
+ SILC_CLIENT_CMD_REPLY(oper, OPER),
+ SILC_CLIENT_CMD_REPLY(join, JOIN),
+ SILC_CLIENT_CMD_REPLY(motd, MOTD),
+ SILC_CLIENT_CMD_REPLY(umode, UMODE),
+ SILC_CLIENT_CMD_REPLY(cmode, CMODE),
+ SILC_CLIENT_CMD_REPLY(kick, KICK),
+ SILC_CLIENT_CMD_REPLY(restart, RESTART),
+ SILC_CLIENT_CMD_REPLY(close, CLOSE),
+ SILC_CLIENT_CMD_REPLY(die, DIE),
+ SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
+ SILC_CLIENT_CMD_REPLY(leave, LEAVE),
+ SILC_CLIENT_CMD_REPLY(names, LEAVE),
+
+ { NULL, 0 },
+};
+
+/* Status message structure. Messages are defined below. */
+typedef struct {
+ SilcCommandStatus status;
+ char *message;
+} SilcCommandStatusMessage;
+
+/* Status messages returned by the server */
+#define STAT(x) SILC_STATUS_ERR_##x
+const SilcCommandStatusMessage silc_command_status_messages[] = {
+
+ { STAT(NO_SUCH_NICK), "No such nickname" },
+ { STAT(NO_SUCH_CHANNEL), "No such channel" },
+ { STAT(NO_SUCH_SERVER), "No such server" },
+ { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
+ { STAT(NO_RECIPIENT), "No recipient given" },
+ { STAT(UNKNOWN_COMMAND), "Unknown command" },
+ { STAT(WILDCARDS), "Unknown command" },
+ { STAT(NO_CLIENT_ID), "No Client ID given" },
+ { STAT(NO_CHANNEL_ID), "No Channel ID given" },
+ { STAT(BAD_CLIENT_ID), "Bad Client ID" },
+ { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
+ { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
+ { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
+ { STAT(NICKNAME_IN_USE), "Nickname already exists" },
+ { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
+ { STAT(USER_ON_CHANNEL), "User already on channel" },
+ { STAT(NOT_REGISTERED), "You have not registered" },
+ { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
+ { STAT(TOO_MANY_PARAMS), "Too many parameters" },
+ { STAT(PERM_DENIED), "Your host is not among the privileged" },
+ { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
+ { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
+ { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
+ { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
+ { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
+ { STAT(UNKNOWN_MODE), "Unknown mode" },
+ { STAT(NOT_YOU), "Cannot change mode for other users" },
+ { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
+ { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
+ { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
+ { STAT(BAD_NICKNAME), "Bad nickname" },
+ { STAT(BAD_CHANNEL), "Bad channel name" },
+ { STAT(AUTH_FAILED), "Authentication failed" },
+
+ { 0, NULL }
+};
+
+/* Process received command reply. */
+
+void silc_client_command_reply_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcClientCommandReplyContext ctx;
+ SilcCommandPayload payload;
+
+ /* Get command reply payload from packet */
+ payload = silc_command_parse_payload(buffer);
+ if (!payload) {
+ /* Silently ignore bad reply packet */
+ SILC_LOG_DEBUG(("Bad command reply packet"));
+ return;
+ }
+
+ /* Allocate command reply context. This must be free'd by the
+ command reply routine receiving it. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->sock = sock;
+ ctx->payload = payload;
+
+ /* Check for pending commands and mark to be exeucted */
+ SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
+
+ /* Execute command reply */
+ SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
+}
+
+/* Returns status message string */
+
+static char *
+silc_client_command_status_message(SilcCommandStatus status)
+{
+ int i;
+
+ for (i = 0; silc_command_status_messages[i].message; i++) {
+ if (silc_command_status_messages[i].status == status)
+ break;
+ }
+
+ if (silc_command_status_messages[i].message == NULL)
+ return NULL;
+
+ return silc_command_status_messages[i].message;
+}
+
+/* Free command reply context and its internals. */
+
+void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
+{
+ if (cmd) {
+ silc_command_free_payload(cmd->payload);
+ silc_free(cmd);
+ }
+}
+
+/* Received reply for WHOIS command. This maybe called several times
+ for one WHOIS command as server may reply with list of results. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(whois)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClient client = cmd->client;
+ SilcCommandStatus status;
+ unsigned char *tmp;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK) {
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ tmp += 2;
+ silc_say(cmd->client, "%s: %s", tmp,
+ silc_client_command_status_message(status));
+ goto out;
+ } else {
+ silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+ goto out;
+ }
+ }
+
+ /* Display one whois reply */
+ if (status == SILC_STATUS_OK) {
+ char buf[256];
+ int argc, len;
+ unsigned char *id_data;
+ char *nickname = NULL, *username = NULL;
+ char *realname = NULL;
+ void *id;
+
+ memset(buf, 0, sizeof(buf));
+
+ argc = silc_command_get_arg_num(cmd->payload);
+ id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
+
+ nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
+ if (nickname) {
+ strncat(buf, nickname, len);
+ strncat(buf, " is ", 4);
+ }
+
+ username = silc_command_get_arg_type(cmd->payload, 4, &len);
+ if (username) {
+ strncat(buf, username, len);
+ }
+
+ realname = silc_command_get_arg_type(cmd->payload, 5, &len);
+ if (realname) {
+ strncat(buf, " (", 2);
+ strncat(buf, realname, len);
+ strncat(buf, ")", 1);
+ }
+
+#if 0
+ /* Save received Client ID to ID cache */
+ /* XXX Maybe should not be saved as /MSG will get confused */
+ id = silc_id_str2id(id_data, SILC_ID_CLIENT);
+ client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
+ silc_idcache_add(&client->current_win->
+ client_id_cache[(int)nickname[0] - 32],
+ client->current_win->
+ client_id_cache_count[(int)nickname[0] - 32],
+ strdup(nickname), SILC_ID_CLIENT, id, NULL);
+#endif
+
+ silc_say(cmd->client, "%s", buf);
+ }
+
+ if (status == SILC_STATUS_LIST_START) {
+
+ }
+
+ if (status == SILC_STATUS_LIST_END) {
+
+ }
+
+ SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
+
+ out:
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(whowas)
+{
+}
+
+/* Received reply for IDENTIFY command. This maybe called several times
+ for one IDENTIFY command as server may reply with list of results.
+ This is totally silent and does not print anything on screen. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(identify)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
+ SilcClientEntry client_entry;
+ SilcCommandStatus status;
+ unsigned char *tmp;
+
+ SILC_LOG_DEBUG(("Start"));
+
+#define CIDC(x) win->client_id_cache[(x) - 32]
+#define CIDCC(x) win->client_id_cache_count[(x) - 32]
+
+ tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK) {
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ tmp += 2;
+ silc_say(cmd->client, "%s: %s", tmp,
+ silc_client_command_status_message(status));
+ goto out;
+ } else {
+ silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+ goto out;
+ }
+ }
+
+ /* Display one whois reply */
+ if (status == SILC_STATUS_OK) {
+ unsigned char *id_data;
+ char *nickname;
+
+ id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
+ nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
+
+ /* Allocate client entry */
+ client_entry = silc_calloc(1, sizeof(*client_entry));
+ client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
+ client_entry->nickname = strdup(nickname);
+
+ /* Save received Client ID to ID cache */
+ CIDCC(nickname[0]) =
+ silc_idcache_add(&CIDC(nickname[0]), CIDCC(nickname[0]),
+ client_entry->nickname, SILC_ID_CLIENT,
+ client_entry->id, client_entry);
+ }
+
+ if (status == SILC_STATUS_LIST_START) {
+
+ }
+
+ if (status == SILC_STATUS_LIST_END) {
+
+ }
+
+ SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
+
+ out:
+ silc_client_command_reply_free(cmd);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Received reply for command NICK. If everything went without errors
+ we just received our new Client ID. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(nick)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
+ SilcCommandStatus status;
+ unsigned char *tmp, *id_string;
+ int argc;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK) {
+ silc_say(cmd->client, "Cannot set nickname: %s",
+ silc_client_command_status_message(status));
+ goto out;
+ }
+
+ argc = silc_command_get_arg_num(cmd->payload);
+ if (argc < 2 || argc > 2) {
+ silc_say(cmd->client, "Cannot set nickname: bad reply to command");
+ goto out;
+ }
+
+ /* Take received Client ID */
+ id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
+ silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
+
+ /* Update nickname on screen */
+ cmd->client->screen->bottom_line->nickname = win->nickname;
+ silc_screen_print_bottom_line(cmd->client->screen, 0);
+
+ out:
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(list)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(topic)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(invite)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(quit)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(kill)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(info)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(away)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(connect)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(ping)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(oper)
+{
+}
+
+/* Received reply for JOIN command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(join)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClient client = cmd->client;
+ SilcCommandStatus status;
+ unsigned int argc;
+ unsigned char *id_string;
+ char *topic, *tmp, *channel_name;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK) {
+ silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+ goto out;
+ }
+
+ argc = silc_command_get_arg_num(cmd->payload);
+ if (argc < 3 || argc > 4) {
+ silc_say(cmd->client, "Cannot join channel: Bad reply packet");
+ goto out;
+ }
+
+ /* Get channel name */
+ tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
+ channel_name = strdup(tmp);
+
+ /* Get channel ID */
+ id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
+
+ /* Get topic */
+ topic = silc_command_get_arg_type(cmd->payload, 4, NULL);
+
+ /* Save received Channel ID */
+ silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, id_string);
+
+ /* Print channel name on screen */
+ client->screen->bottom_line->channel = channel_name;
+ silc_screen_print_bottom_line(client->screen, 0);
+
+ if (topic)
+ silc_say(client, "Topic for %s: %s", channel_name, topic);
+
+ out:
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(motd)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(umode)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(cmode)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(kick)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(restart)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(close)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(die)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(leave)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(names)
+{
+}
+
+/* Private message received. This processes the private message and
+ finally displays it on the screen. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(msg)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClient client = cmd->client;
+ SilcBuffer buffer = (SilcBuffer)cmd->context;
+ unsigned short nick_len;
+ unsigned char *nickname, *message;
+ SilcIDCache *id_cache;
+ unsigned char *id_string;
+ void *id;
+
+ /* Get nickname */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
+ SILC_STR_END);
+ silc_buffer_pull(buffer, 2 + nick_len);
+
+#if 0
+ /* Get ID of the sender */
+ id_string = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char *));
+ silc_buffer_push(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
+ memcpy(id_string, buffer->data, SILC_ID_CLIENT_LEN);
+ silc_buffer_pull(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
+ id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+ silc_free(id_string);
+
+ /* Nickname should be verified if we don't have it in the cache */
+ if (silc_idcache_find_by_data(client->current_win->
+ client_id_cache[nickname[0] - 32],
+ client->current_win->
+ client_id_cache_count[nickname[0] - 32],
+ nickname, &id_cache) == FALSE) {
+
+ SilcClientCommandContext ctx;
+ char whois[255];
+
+ /* Private message from unknown source, try to resolve it. */
+
+
+ return;
+ }
+#endif
+
+ message = silc_calloc(buffer->len + 1, sizeof(char));
+ memcpy(message, buffer->data, buffer->len);
+ silc_print(client, "*%s* %s", nickname, message);
+ memset(message, 0, buffer->len);
+ silc_free(message);
+}
--- /dev/null
+/*
+
+ command_reply.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_REPLY_H
+#define COMMAND_REPLY_H
+
+/* Structure holding one command reply and pointer to its function. */
+typedef struct {
+ SilcCommandCb cb;
+ SilcCommand cmd;
+} SilcClientCommandReply;
+
+/* All client command replys */
+extern SilcClientCommandReply silc_command_reply_list[];
+
+/* Context sent as argument to all command reply functions */
+typedef struct {
+ SilcClient client;
+ SilcSocketConnection sock;
+ SilcCommandPayload payload;
+
+ /* If defined this executes the pending command. */
+ void *context;
+ SilcClientCommandCallback callback;
+} *SilcClientCommandReplyContext;
+
+/* Macros */
+
+/* Macro used for command declaration in command reply list structure */
+#define SILC_CLIENT_CMD_REPLY(func, cmd ) \
+{ silc_client_command_reply_##func, SILC_COMMAND_##cmd }
+
+/* Macro used to declare command reply functions */
+#define SILC_CLIENT_CMD_REPLY_FUNC(func) \
+void silc_client_command_reply_##func(void *context)
+
+/* Macro used to execute command replies */
+#define SILC_CLIENT_COMMAND_REPLY_EXEC(ctx) \
+do { \
+ SilcClientCommandReply *cmd; \
+ \
+ for (cmd = silc_command_reply_list; cmd->cb; cmd++) \
+ if (cmd->cmd == silc_command_get(ctx->payload)) { \
+ cmd->cb(ctx); \
+ break; \
+ } \
+ \
+ if (cmd == NULL) { \
+ silc_free(ctx); \
+ return; \
+ } \
+} while(0)
+
+/* Prototypes */
+void silc_client_command_reply_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer buffer);
+SILC_CLIENT_CMD_REPLY_FUNC(whois);
+SILC_CLIENT_CMD_REPLY_FUNC(whowas);
+SILC_CLIENT_CMD_REPLY_FUNC(identify);
+SILC_CLIENT_CMD_REPLY_FUNC(nick);
+SILC_CLIENT_CMD_REPLY_FUNC(list);
+SILC_CLIENT_CMD_REPLY_FUNC(topic);
+SILC_CLIENT_CMD_REPLY_FUNC(invite);
+SILC_CLIENT_CMD_REPLY_FUNC(quit);
+SILC_CLIENT_CMD_REPLY_FUNC(kill);
+SILC_CLIENT_CMD_REPLY_FUNC(info);
+SILC_CLIENT_CMD_REPLY_FUNC(links);
+SILC_CLIENT_CMD_REPLY_FUNC(stats);
+SILC_CLIENT_CMD_REPLY_FUNC(users);
+SILC_CLIENT_CMD_REPLY_FUNC(away);
+SILC_CLIENT_CMD_REPLY_FUNC(connect);
+SILC_CLIENT_CMD_REPLY_FUNC(ping);
+SILC_CLIENT_CMD_REPLY_FUNC(pong);
+SILC_CLIENT_CMD_REPLY_FUNC(oper);
+SILC_CLIENT_CMD_REPLY_FUNC(join);
+SILC_CLIENT_CMD_REPLY_FUNC(motd);
+SILC_CLIENT_CMD_REPLY_FUNC(umode);
+SILC_CLIENT_CMD_REPLY_FUNC(cmode);
+SILC_CLIENT_CMD_REPLY_FUNC(kick);
+SILC_CLIENT_CMD_REPLY_FUNC(restart);
+SILC_CLIENT_CMD_REPLY_FUNC(close);
+SILC_CLIENT_CMD_REPLY_FUNC(die);
+SILC_CLIENT_CMD_REPLY_FUNC(silcoper);
+SILC_CLIENT_CMD_REPLY_FUNC(leave);
+SILC_CLIENT_CMD_REPLY_FUNC(names);
+SILC_CLIENT_CMD_REPLY_FUNC(msg);
+
+#endif
--- /dev/null
+/*
+
+ idlist.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef IDLIST_H
+#define IDLIST_H
+
+/* Client entry context. When client receives information about new client
+ (it receives its ID, for example, by IDENTIFY request) we create new
+ client entry. This entry also includes the private message keys if
+ they are used. */
+typedef struct SilcClientEntryStruct {
+ char *nickname;
+ SilcClientID *id;
+
+ /* Keys, these are defined if private message key has been defined
+ with the remote client. */
+ SilcCipher send_key;
+ SilcCipher receive_key;
+} SilcClientEntryObject;
+
+typedef SilcClientEntryObject *SilcClientEntry;
+
+/* Channel entry context. This is allocate for every channel client has
+ joined to. This includes for example the channel specific keys */
+/* XXX channel_key is the server generated key. Later this context must
+ include the channel private key. */
+typedef struct SilcChannelEntryStruct {
+ char *channel_name;
+ SilcChannelID *id;
+ int on_channel;
+
+ /* Channel keys */
+ SilcCipher channel_key;
+ unsigned char *key;
+ unsigned int key_len;
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
+} SilcChannelEntryObject;
+
+typedef SilcChannelEntryObject *SilcChannelEntry;
+
+#endif
--- /dev/null
+/*
+
+ protocol.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Client side of the protocols.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
+SILC_TASK_CALLBACK(silc_client_protocol_channel_auth);
+SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
+
+/* SILC client protocol list */
+const SilcProtocolObject silc_protocol_list[] =
+{
+ { SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+ silc_client_protocol_connection_auth },
+ { SILC_PROTOCOL_CLIENT_CHANNEL_AUTH,
+ silc_client_protocol_channel_auth },
+ { SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ silc_client_protocol_key_exchange },
+
+ { SILC_PROTOCOL_CLIENT_NONE, NULL },
+};
+
+/*
+ * Key Exhange protocol functions
+ */
+
+static void silc_client_protocol_ke_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ /* Send the packet immediately */
+ silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+
+}
+
+static void silc_client_protocol_ke_phase1_cb(SilcSKE ske,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ SILC_LOG_DEBUG(("Start"));
+
+}
+
+static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ SILC_LOG_DEBUG(("Start"));
+
+}
+
+/* Sets the negotiated key material into use for particular connection. */
+
+static void silc_client_protocol_ke_set_keys(SilcSKE ske,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat,
+ SilcCipher cipher,
+ SilcPKCS pkcs,
+ SilcHash hash)
+{
+ SilcClientWindow win = (SilcClientWindow)sock->user_data;
+ SilcHash nhash;
+
+ SILC_LOG_DEBUG(("Setting new keys into use"));
+
+ /* Allocate cipher to be used in the communication */
+ silc_cipher_alloc(cipher->cipher->name, &win->send_key);
+ silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
+
+ win->send_key->cipher->set_key(win->send_key->context,
+ keymat->send_enc_key,
+ keymat->enc_key_len);
+ win->send_key->set_iv(win->send_key, keymat->send_iv);
+ win->receive_key->cipher->set_key(win->receive_key->context,
+ keymat->receive_enc_key,
+ keymat->enc_key_len);
+ win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
+
+ /* Allocate PKCS to be used */
+#if 0
+ /* XXX Do we ever need to allocate PKCS for the connection??
+ If yes, we need to change KE protocol to get the initiators
+ public key. */
+ silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
+ silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data,
+ ske->ke2_payload->pk_len);
+#endif
+
+ /* Save HMAC key to be used in the communication. */
+ silc_hash_alloc(hash->hash->name, &nhash);
+ silc_hmac_alloc(nhash, &win->hmac);
+ win->hmac_key_len = keymat->hmac_key_len;
+ win->hmac_key = silc_calloc(win->hmac_key_len,
+ sizeof(unsigned char));
+ memcpy(win->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
+
+}
+
+/* Performs key exchange protocol. This is used for both initiator
+ and responder key exchange. This may be called recursively. */
+
+SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcSKEStatus status;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start Protocol
+ */
+ SilcSKE ske;
+
+ /* Allocate Key Exchange object */
+ ske = silc_ske_alloc();
+ ctx->ske = ske;
+
+ if (ctx->responder == TRUE) {
+#if 0
+ SilcBuffer start_payload;
+
+
+ /* Start the key exchange by processing the received security
+ properties packet from initiator. */
+ status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+ start_payload,
+ silc_client_protocol_ke_send_packet,
+ context);
+#endif
+ } else {
+ SilcSKEStartPayload *start_payload;
+
+ /* Assemble security properties. */
+ silc_ske_assemble_security_properties(ske, &start_payload);
+
+ /* Start the key exchange by sending our security properties
+ to the remote end. */
+ status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
+ start_payload,
+ silc_client_protocol_ke_send_packet,
+ context);
+ }
+
+ if (status != SILC_SKE_STATUS_OK) {
+ switch(status) {
+
+ default:
+ break;
+ }
+ }
+
+ /* Advance the state of the protocol. */
+ protocol->state++;
+ }
+ break;
+ case 2:
+ {
+ /*
+ * Phase 1
+ */
+ if (ctx->responder == TRUE) {
+#if 0
+ status =
+ silc_ske_responder_phase_1(ctx->ske,
+ ctx->ske->start_payload,
+ silc_server_protocol_ke_send_packet,
+ context);
+#endif
+ } else {
+ /* Call Phase-1 function. This processes the Key Exchange Start
+ paylaod reply we just got from the responder. The callback
+ function will receive the processed payload where we will
+ save it. */
+ status =
+ silc_ske_initiator_phase_1(ctx->ske,
+ ctx->packet,
+ silc_client_protocol_ke_phase1_cb,
+ context);
+ }
+
+ switch(status) {
+ default:
+ break;
+ }
+
+ /* Advance the state of the protocol and call the next state. */
+ protocol->state++;
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+ }
+ break;
+ case 3:
+ {
+ /*
+ * Phase 2
+ */
+ if (ctx->responder == TRUE) {
+#if 0
+ status =
+ silc_ske_responder_phase_2(ctx->ske,
+ ctx->ske->start_payload,
+ silc_server_protocol_ke_send_packet,
+ context);
+#endif
+ } else {
+ /* Call the Phase-2 function. This creates Diffie Hellman
+ key exchange parameters and sends our public part inside
+ Key Exhange 1 Payload to the responder. */
+ status =
+ silc_ske_initiator_phase_2(ctx->ske,
+ silc_client_protocol_ke_send_packet,
+ context);
+ }
+
+ switch(status) {
+ default:
+ break;
+ }
+
+ /* Advance the state of the protocol. */
+ protocol->state++;
+ }
+ break;
+ case 4:
+ {
+ /*
+ * Finish protocol
+ */
+ if (ctx->responder == TRUE) {
+#if 0
+ status =
+ silc_ske_responder_phase_2(ctx->ske,
+ ctx->ske->start_payload,
+ silc_server_protocol_ke_send_packet,
+ context);
+#endif
+ } else {
+ /* Finish the protocol. This verifies the Key Exchange 2 payload
+ sent by responder. */
+ status =
+ silc_ske_initiator_finish(ctx->ske,
+ ctx->packet,
+ silc_client_protocol_ke_finish_cb,
+ context);
+ }
+
+ switch(status) {
+ default:
+ break;
+ }
+
+ /* Send Ok to the other end. We will end the protocol as server
+ sends Ok to us when we will take the new keys into use. */
+ silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
+
+ /* End the protocol on the next round */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+ break;
+ case SILC_PROTOCOL_STATE_END:
+ {
+ /*
+ * End protocol
+ */
+ SilcSKEKeyMaterial *keymat;
+
+ /* Process the key material */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
+
+ /* Take the negotiated keys into use. */
+ silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
+ ctx->ske->prop->cipher,
+ ctx->ske->prop->pkcs,
+ ctx->ske->prop->hash);
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+ case SILC_PROTOCOL_STATE_ERROR:
+
+ /* On error the final callback is always called. */
+ /* protocol->final_callback(pptr, context);*/
+ break;
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+}
+
+/*
+ * Connection Authentication protocol functions
+ */
+
+SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientConnAuthInternalContext *ctx =
+ (SilcClientConnAuthInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start protocol. We send authentication data to the server
+ * to be authenticated.
+ */
+ SilcBuffer packet;
+ int payload_len = 0;
+ unsigned char *auth_data = NULL;
+ unsigned int auth_data_len = 0;
+
+ switch(ctx->auth_meth) {
+ case SILC_PROTOCOL_CONN_AUTH_NONE:
+ /* No authentication required */
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+ /* Password authentication */
+ if (ctx->auth_data && ctx->auth_data_len) {
+ auth_data = ctx->auth_data;
+ auth_data_len = ctx->auth_data_len;
+ break;
+ }
+
+ silc_say(client, "Password authentication required by server %s",
+ ctx->sock->hostname);
+ auth_data = silc_client_ask_passphrase(client);
+ auth_data_len = strlen(auth_data);
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+#if 0
+
+#endif
+ break;
+ }
+
+ payload_len = 4 + auth_data_len;
+ packet = silc_buffer_alloc(payload_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(payload_len),
+ SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
+ SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
+ SILC_STR_END);
+
+ /* Send the packet to server */
+ silc_client_packet_send(client, ctx->sock,
+ SILC_PACKET_CONNECTION_AUTH,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+
+ if (auth_data) {
+ memset(auth_data, 0, auth_data_len);
+ silc_free(auth_data);
+ }
+ silc_buffer_free(packet);
+
+ /* Next state is end of protocol */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_END:
+ {
+ /*
+ * End protocol. Nothing special to be done here.
+ */
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_ERROR:
+ {
+ /*
+ * Error
+ */
+
+ /* Error in protocol. Send FAILURE packet. Although I don't think
+ this could ever happen on client side. */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
+ NULL, 0, NULL, NULL, NULL, 0, TRUE);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+}
+
+SILC_TASK_CALLBACK(silc_client_protocol_channel_auth)
+{
+}
--- /dev/null
+/*
+
+ protocol.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+/* SILC client protocol types */
+#define SILC_PROTOCOL_CLIENT_NONE 0
+#define SILC_PROTOCOL_CLIENT_CONNECTION_AUTH 1
+#define SILC_PROTOCOL_CLIENT_CHANNEL_AUTH 2
+#define SILC_PROTOCOL_CLIENT_KEY_EXCHANGE 3
+/* #define SILC_PROTOCOL_CLIENT_MAX 255 */
+
+/* Internal context for key exchange protocol */
+typedef struct {
+ void *client;
+ SilcSocketConnection sock;
+ SilcRng rng;
+ int responder;
+ SilcBuffer packet;
+ SilcSKE ske;
+} SilcClientKEInternalContext;
+
+/* Internal context for connection authentication protocol */
+typedef struct {
+ void *client;
+ SilcSocketConnection sock;
+
+ /* SKE object from Key Exchange protocol. */
+ SilcSKE ske;
+
+ /* Auth method that must be used. This is resolved before this
+ connection authentication protocol is started. */
+ unsigned int auth_meth;
+
+ /* Authentication data if we alreay know it. This is filled before
+ starting the protocol if we know the authentication data. Otherwise
+ these are and remain NULL. */
+ unsigned char *auth_data;
+ unsigned int auth_data_len;
+
+ SilcTask timeout_task;
+} SilcClientConnAuthInternalContext;
+
+/* Prototypes */
+
+#endif
--- /dev/null
+/*
+
+ screen.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * SILC client screen routines. These implement the user interface
+ * on ncurses routines. Most of these routines were taken from the
+ * old version of the SILC client dating back to 1997.
+ */
+/* XXX: Input line handling is really buggy! */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+SilcScreen silc_screen_init()
+{
+ SilcScreen new;
+
+ new = silc_malloc(sizeof(*new));
+ if (new == NULL) {
+ SILC_LOG_ERROR(("Could not create new screen object"));
+ return NULL;
+ }
+
+ new->output_win_count = 0;
+ new->input_pos = 0;
+ new->cursor_pos = 0;
+ new->virtual_window = 0;
+ new->insert = TRUE;
+
+ initscr();
+ cbreak();
+ nonl();
+ noecho();
+
+ silc_screen_create_output_window(new);
+ silc_screen_create_input_window(new);
+
+ return new;
+}
+
+/* Creates one (main) output window. Returns new created physical
+ window. */
+
+WINDOW *silc_screen_create_output_window(SilcScreen screen)
+{
+ assert(screen != NULL);
+
+ screen->output_win = silc_malloc(sizeof(*screen->output_win) * 1);
+ screen->output_win_count = 1;
+ screen->output_win[0] = newwin(LINES - 3, COLS, 1, 0);
+ scrollok(screen->output_win[0], TRUE);
+ idlok(screen->output_win[0], TRUE);
+ wrefresh(screen->output_win[0]);
+
+ return screen->output_win[0];
+}
+
+/* Adds new output window. Return new created physical window. */
+
+WINDOW *silc_screen_add_output_window(SilcScreen screen)
+{
+ int i;
+
+ assert(screen != NULL);
+
+ screen->output_win = silc_realloc(screen->output_win,
+ (screen->output_win_count + 1) *
+ sizeof(*screen->output_win));
+ i = screen->output_win_count;
+ screen->output_win[i] = newwin(LINES - 3, COLS, 1, 0);
+ scrollok(screen->output_win[i], TRUE);
+ idlok(screen->output_win[i], TRUE);
+ wrefresh(screen->output_win[i]);
+ screen->output_win_count++;
+
+ return screen->output_win[i];
+}
+
+void silc_screen_create_input_window(SilcScreen screen)
+{
+ assert(screen != NULL);
+
+ screen->input_win = newwin(0, COLS, LINES - 1, 0);
+ scrollok(screen->input_win, TRUE);
+ keypad(screen->input_win, TRUE);
+ wrefresh(screen->input_win);
+}
+
+void silc_screen_init_upper_status_line(SilcScreen screen)
+{
+ int i;
+ int justify;
+
+ assert(screen != NULL);
+
+ /* Create upper status line */
+ screen->upper_stat_line = newwin(0, COLS, 0, 0);
+ scrollok(screen->upper_stat_line, FALSE);
+ wattrset(screen->upper_stat_line, A_REVERSE);
+
+ /* Print empty line */
+ for (i = 0; i < COLS - 1; i++)
+ mvwprintw(screen->upper_stat_line, 0, i, " ");
+
+ /* Print stuff with justify */
+ justify = COLS / 5;
+ mvwprintw(screen->upper_stat_line, 0, 1, "%s %s",
+ screen->u_stat_line.program_name,
+ screen->u_stat_line.program_version);
+ /*
+ mvwprintw(screen->upper_stat_line, 0, justify, "[Your Connection: %s]",
+ stat.uconnect_status[stat.uconnect]);
+ mvwprintw(screen->upper_stat_line, 0,
+ (justify + justify + justify), "[SILC: %s]",
+ stat.silc_status[stat.silc]);
+ */
+
+ /* Prints clock on upper stat line */
+ silc_screen_print_clock(screen);
+ wrefresh(screen->upper_stat_line);
+}
+
+void silc_screen_init_output_status_line(SilcScreen screen)
+{
+ int i;
+
+ assert(screen != NULL);
+
+ screen->output_stat_line = silc_calloc(1, sizeof(*screen->output_stat_line));
+
+ screen->output_stat_line[0] = newwin(1, COLS, LINES - 2, 0);
+ scrollok(screen->output_stat_line[0], FALSE);
+ wattrset(screen->output_stat_line[0], A_REVERSE);
+
+ /* print first just blank line */
+ for (i = 0; i < COLS - 1; i++)
+ mvwprintw(screen->output_stat_line[0], 0, i, " ");
+
+ /* Allocate bottom line */
+ screen->bottom_line = silc_calloc(1, sizeof(*screen->bottom_line));
+
+ wattrset(screen->output_stat_line[0], A_NORMAL);
+ wrefresh(screen->output_stat_line[0]);
+}
+
+void silc_screen_print_clock(SilcScreen screen)
+{
+ time_t curtime;
+ struct tm *tp;
+
+ curtime = time(0);
+ tp = localtime(&curtime);
+
+ mvwprintw(screen->upper_stat_line, 0, COLS - 8, "[%02d:%02d] ",
+ tp->tm_hour, tp->tm_min);
+ wrefresh(screen->upper_stat_line);
+}
+
+/* Prints current cursor coordinates on some output stat line */
+
+void silc_screen_print_coordinates(SilcScreen screen, int win_index)
+{
+ wattrset(screen->output_stat_line[win_index], A_REVERSE);
+ mvwprintw(screen->output_stat_line[win_index], 0, COLS - 10,
+ "[%4d,%3d]", screen->input_pos, LINES);
+ wrefresh(screen->output_stat_line[win_index]);
+ wattrset(screen->output_stat_line[win_index], A_NORMAL);
+}
+
+/* Prints bottom line (the status line) of the screen. */
+
+void silc_screen_print_bottom_line(SilcScreen screen, int win_index)
+{
+ char buf[512];
+ SilcScreenBottomLine line = screen->bottom_line;
+ int i, len;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (line->mode) {
+ len = strlen(line->mode);
+ strncat(buf, line->mode, len);
+ }
+
+ if (line->nickname) {
+ len = strlen(line->nickname);
+ strncat(buf, line->nickname, len > SILC_SCREEN_MAX_NICK_LEN ?
+ SILC_SCREEN_MAX_NICK_LEN : len);
+ }
+
+ if (line->connection) {
+ len = strlen(line->connection);
+ strncat(buf, " via ", 5);
+ strncat(buf, line->connection, len > SILC_SCREEN_MAX_CONN_LEN ?
+ SILC_SCREEN_MAX_CONN_LEN : len);
+ }
+
+ if (line->channel) {
+ len = strlen(line->channel);
+ strncat(buf, " ", 1);
+ strncat(buf, line->channel, len > SILC_SCREEN_MAX_CHANNEL_LEN ?
+ SILC_SCREEN_MAX_CHANNEL_LEN : len);
+ }
+
+ wattrset(screen->output_stat_line[win_index], A_REVERSE);
+
+ for (i = 0; i < COLS - 10; i++)
+ mvwprintw(screen->output_stat_line[win_index], 0, i, " ");
+
+ mvwprintw(screen->output_stat_line[win_index], 0, 0, " %s", buf);
+ silc_screen_print_coordinates(screen, win_index);
+ wrefresh(screen->output_stat_line[win_index]);
+ wattrset(screen->output_stat_line[win_index], A_NORMAL);
+}
+
+/* Refresh all windows */
+
+void silc_screen_refresh_all(SilcScreen screen)
+{
+ int i;
+
+ assert(screen != NULL);
+
+ redrawwin(screen->upper_stat_line);
+
+ for (i = 0; i < screen->output_win_count; i++) {
+ wrefresh(screen->output_win[i]);
+ redrawwin(screen->output_win[i]);
+ }
+
+ wrefresh(screen->input_win);
+ redrawwin(screen->input_win);
+}
+
+/* Refreshes a window */
+
+void silc_screen_refresh_win(WINDOW *win)
+{
+ assert(win != NULL);
+
+ redrawwin(win);
+ wrefresh(win);
+}
+
+/* Resets input window */
+
+void silc_screen_input_reset(SilcScreen screen)
+{
+ int i;
+
+ assert(screen != NULL);
+ for (i = 0; i < COLS - 1; i++)
+ mvwprintw(screen->input_win, 0, i, " ");
+ mvwprintw(screen->input_win, 0, 0, "");
+ wrefresh(screen->input_win);
+ screen->input_pos = 0;
+ screen->input_end = 0;
+ screen->cursor_pos = 0;
+ screen->virtual_window = 0;
+}
+
+/* Backspace. Removes one character from input windows. */
+
+void silc_screen_input_backspace(SilcScreen screen)
+{
+ WINDOW *win;
+ char *buffer;
+
+ assert(screen != NULL);
+ buffer = screen->input_buffer;
+ win = screen->input_win;
+
+ /* Return directly if at the start of input line */
+ if (screen->input_pos == 0)
+ return;
+
+ if (screen->virtual_window) {
+ if (screen->cursor_pos <= 10) {
+ int i;
+
+ /* Clear line */
+ for (i = 0; i < COLS; i++)
+ mvwprintw(win, 0, i, " ");
+ mvwprintw(win, 0, 0, "");
+
+ screen->virtual_window--;
+
+ waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
+ screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
+ screen->input_end = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
+ screen->cursor_pos = (COLS - 5) + 1;
+ wrefresh(win);
+ }
+ }
+
+ screen->cursor_pos--;
+ screen->input_pos--;
+ screen->input_end--;
+ mvwdelch(win, 0, screen->cursor_pos);
+
+ if (screen->input_pos < screen->input_end)
+ /* Delete from inside the input line */
+ SILC_SCREEN_INPUT_DELETE(buffer, screen->input_pos, screen->input_end);
+ else
+ /* Delete from the end of the input line */
+ buffer[screen->input_pos] = 0;
+
+ wrefresh(win);
+}
+
+/* Switches insert on input window on/off */
+
+void silc_screen_input_insert(SilcScreen screen)
+{
+ assert(screen != NULL);
+
+ screen->insert = screen->insert == TRUE ? FALSE : TRUE;
+}
+
+/* Moves cursor one character length to rightward */
+
+void silc_screen_input_cursor_right(SilcScreen screen)
+{
+ WINDOW *win;
+ char *buffer;
+
+ assert(screen != NULL);
+ buffer = screen->input_buffer;
+ win = screen->input_win;
+
+ /* Return directly if we are at the end of input line */
+ if (screen->cursor_pos >= SILC_SCREEN_INPUT_WIN_SIZE)
+ return;
+
+ /* Make sure cursor doesn't advance over the end of the line */
+ if (screen->input_pos >= screen->input_end)
+ return;
+
+ /* When cursor advances enough we switch to new window and show
+ rest of the typed characters on the screen. */
+ if (screen->cursor_pos >= (COLS - 5)) {
+ int i;
+
+ /* Clear line */
+ for (i = 0; i < COLS; i++)
+ mvwprintw(win, 0, i, " ");
+ mvwprintw(win, 0, 0, "");
+
+ waddnstr(win, &buffer[screen->input_pos - 10],
+ ((screen->input_pos - 10) - screen->input_end >= COLS) ?
+ COLS : (screen->input_pos - 10) - screen->input_end);
+ screen->cursor_pos = 10;
+ wrefresh(win);
+
+ screen->virtual_window++;
+ }
+
+ screen->cursor_pos++;
+ screen->input_pos++;
+ wmove(win, 0, screen->cursor_pos);
+ wrefresh(win);
+}
+
+/* Moves cursor one character length to leftward */
+
+void silc_screen_input_cursor_left(SilcScreen screen)
+{
+ WINDOW *win;
+ char *buffer;
+
+ assert(screen != NULL);
+ buffer = screen->input_buffer;
+ win = screen->input_win;
+
+ /* Return directly if at the start of input line */
+ if (screen->input_pos == 0)
+ return;
+
+ /* When cursor advances enough we switch to new window and show
+ rest of the typed characters on the screen. */
+ if (screen->virtual_window) {
+ if (screen->cursor_pos <= 10) {
+ int i;
+
+ /* Clear line */
+ for (i = 0; i < COLS; i++)
+ mvwprintw(win, 0, i, " ");
+ mvwprintw(win, 0, 0, "");
+
+ screen->virtual_window--;
+
+ waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
+ screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
+ screen->cursor_pos = (COLS - 5) + 1;
+ wrefresh(win);
+ }
+ }
+
+ screen->cursor_pos--;
+ screen->input_pos--;
+ wmove(win, 0, screen->cursor_pos);
+ wrefresh(win);
+}
+
+/* Moves cursor at the very start of the input line */
+
+void silc_screen_input_cursor_home(SilcScreen screen)
+{
+ WINDOW *win;
+ char *buffer;
+
+ assert(screen != NULL);
+ buffer = screen->input_buffer;
+ win = screen->input_win;
+
+ wclear(win);
+ waddnstr(win, &buffer[0], COLS);
+ wrefresh(win);
+
+ screen->input_pos = 0;
+ screen->cursor_pos = 0;
+ screen->virtual_window = 0;
+}
+
+/* Moves cursor at the very end of the input line */
+
+void silc_screen_input_cursor_end(SilcScreen screen)
+{
+ WINDOW *win;
+ char *buffer;
+
+ assert(screen != NULL);
+ buffer = screen->input_buffer;
+ win = screen->input_win;
+
+ wclear(win);
+ waddnstr(win, &buffer[screen->input_end - 10], 10);
+ wrefresh(win);
+
+ screen->input_pos = screen->input_end;
+ screen->cursor_pos = 10;
+ /* XXX */
+ screen->virtual_window = 0;
+}
+
+/* Prints typed character into the input window for user to see. Character
+ attributes must be set separately outside this function. */
+
+void silc_screen_input_print(SilcScreen screen, unsigned char c)
+{
+ WINDOW *win;
+ char *buffer;
+
+ assert(screen != NULL);
+ buffer = screen->input_buffer;
+ win = screen->input_win;
+
+ /* Return directly if input window is full */
+ if (screen->input_pos >= SILC_SCREEN_INPUT_WIN_SIZE)
+ return;
+
+ /* The input window is COLS wide but one can type into it at most
+ SILC_SCREEN_INPUT_SIZE characters. When COLS - 5 characters is
+ typed the window is cleared and the cursor is moved at the tenth
+ character in the input window. Ten last typed character is then
+ showed at the start of the window. */
+ if (screen->cursor_pos >= (COLS - 5)) {
+ int i;
+
+ /* Clear line */
+ for (i = 0; i < COLS; i++)
+ mvwprintw(win, 0, i, " ");
+ mvwprintw(win, 0, 0, "");
+
+ /* Show ten last typed characters from the buffer on the screen */
+ waddnstr(win, &buffer[screen->input_pos - 10], 10);
+ screen->cursor_pos = 10;
+ wrefresh(win);
+
+ screen->virtual_window++;
+ }
+
+ if (screen->input_pos < screen->input_end) {
+ /* User moved cursor into the typed line. We are not adding
+ character at the end of the line anymore */
+
+ if (screen->insert == FALSE) {
+ /* Add new character somewhere inside typed line. The input
+ line position is not advanced since a character was replaced
+ by the new character. */
+ waddch(win, c);
+ buffer[screen->input_pos] = c;
+ screen->cursor_pos++;
+ screen->input_pos++;
+ screen->input_end = screen->input_pos;
+ } else {
+ /* Insert new character somewhere inside typed line. Other
+ characters are moved forward. We must advance the input line
+ posititon. */
+ winsch(win, c);
+ wmove(win, 0, screen->cursor_pos + 1);
+ SILC_SCREEN_INPUT_INSERT(buffer, screen->input_pos,
+ c, screen->input_end);
+ screen->cursor_pos++;
+ screen->input_pos++;
+ screen->input_end++;
+ }
+ } else {
+ /* Add new character at the end of input line */
+ waddch(win, c);
+ buffer[screen->input_pos] = c;
+ screen->input_pos++;
+ screen->cursor_pos++;
+ screen->input_end = screen->input_pos;
+ }
+
+ /* Advance the cursor position. Cursor moves one to rightward always */
+ wrefresh(win);
+}
+
+/* Prints prompt to the input window. Cursors position aftern printing
+ is length of the prompt. */
+
+void silc_screen_input_print_prompt(SilcScreen screen, char *prompt)
+{
+ WINDOW *win;
+
+ assert(screen != NULL);
+ win = screen->input_win;
+
+ wclear(win);
+ waddnstr(win, prompt, strlen(prompt));
+ wrefresh(win);
+
+ screen->input_pos = strlen(prompt);
+ screen->cursor_pos = strlen(prompt);
+ screen->virtual_window = 0;
+}
--- /dev/null
+/*
+
+ screen.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SCREEN_H
+#define SCREEN_H
+
+typedef struct {
+ char *mode;
+ char *nickname;
+ char *connection;
+ char *channel;
+} *SilcScreenBottomLine;
+
+typedef struct {
+ /* Status line window top of the screen */
+ WINDOW *upper_stat_line;
+
+ /* Output windows */
+ WINDOW **output_win;
+ WINDOW **output_stat_line;
+ unsigned int output_win_count;
+
+ /* Input window at the bottom of the screen */
+ WINDOW *input_win;
+ unsigned char *input_buffer;
+ unsigned int input_pos;
+ unsigned int input_end;
+ unsigned int cursor_pos;
+ int virtual_window;
+
+ /* Bottom line on screen */
+ SilcScreenBottomLine bottom_line;
+
+ /* On/off flag for insert */
+ int insert;
+
+ /* XXX */
+ struct upper_status_line {
+ char *program_name;
+ char *program_version;
+ } u_stat_line;
+
+} SilcScreenObject;
+
+typedef SilcScreenObject *SilcScreen;
+
+/* Size of the input window. User can type this many characters into
+ the window. After that no more characters may be added into the
+ window. */
+#define SILC_SCREEN_INPUT_WIN_SIZE 1024
+
+/* Maximum length of nickaname that will be shown on the screen */
+#define SILC_SCREEN_MAX_NICK_LEN 16
+
+/* Maximum length of channel name that will be shown on the screen */
+#define SILC_SCREEN_MAX_CHANNEL_LEN 20
+
+/* Maximum length of connection name that will be shown on the screen */
+#define SILC_SCREEN_MAX_CONN_LEN 20
+
+/* Macros */
+
+/* Macro used to insert typed character into the buffer. The character
+ is not added at the end of the buffer but somewhere in between. */
+#define SILC_SCREEN_INPUT_INSERT(__x, __y, __ch, __end) \
+do { \
+ unsigned char __tmp[SILC_SCREEN_INPUT_WIN_SIZE + 1]; \
+ memcpy(__tmp, &(__x)[(__y)], (__end) - (__y)); \
+ (__x)[(__y)] = __ch; \
+ memcpy(&(__x)[(__y) + 1], __tmp, (__end) - (__y)); \
+} while(0)
+
+/* Macro used to delete character from the buffer. The character
+ is not removed from the end of the buffer but somewhere in between. */
+#define SILC_SCREEN_INPUT_DELETE(__x, __y, __end) \
+do { \
+ unsigned char __tmp[SILC_SCREEN_INPUT_WIN_SIZE + 1]; \
+ memcpy(__tmp, &(__x)[(__y) + 1], (__end)); \
+ memset(&(__x)[(__y)], 0, (__end) - (__y) + 1); \
+ memcpy(&(__x)[(__y)], __tmp, strlen(__tmp)); \
+} while(0)
+
+/* Prototypes */
+SilcScreen silc_screen_init();
+WINDOW *silc_screen_create_output_window(SilcScreen screen);
+WINDOW *silc_screen_add_output_window(SilcScreen screen);
+void silc_screen_create_input_window(SilcScreen screen);
+void silc_screen_init_upper_status_line(SilcScreen screen);
+void silc_screen_init_output_status_line(SilcScreen screen);
+void silc_screen_print_clock(SilcScreen screen);
+void silc_screen_print_coordinates(SilcScreen screen, int win_index);
+void silc_screen_print_bottom_line(SilcScreen screen, int win_index);
+void silc_screen_refresh_all(SilcScreen screen);
+void silc_screen_refresh_win(WINDOW *win);
+void silc_screen_input_reset(SilcScreen screen);
+void silc_screen_input_backspace(SilcScreen screen);
+void silc_screen_input_insert(SilcScreen screen);
+void silc_screen_input_cursor_right(SilcScreen screen);
+void silc_screen_input_cursor_left(SilcScreen screen);
+void silc_screen_input_cursor_home(SilcScreen screen);
+void silc_screen_input_cursor_end(SilcScreen screen);
+void silc_screen_input_print(SilcScreen screen, unsigned char c);
+void silc_screen_input_print_prompt(SilcScreen screen, char *prompt);
+
+#endif
--- /dev/null
+/*
+
+ silc.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+#include "version.h"
+
+/* Long command line options */
+static struct option long_opts[] =
+{
+ /* Generic options */
+ { "server", 1, NULL, 's' },
+ { "port", 1, NULL, 'p' },
+ { "nickname", 1, NULL, 'n' },
+ { "channel", 1, NULL, 'c' },
+ { "cipher", 1, NULL, 'r' },
+ { "public-key", 1, NULL, 'b' },
+ { "private-key", 1, NULL, 'k' },
+ { "config-file", 1, NULL, 'f' },
+ { "no-silcrc", 0, NULL, 'q' },
+ { "help", 0, NULL, 'h' },
+ { "version", 0, NULL, 'V' },
+ { "list-ciphers", 0, NULL, 1 },
+ { "list-hash-funcs", 0, NULL, 2 },
+ { "list-pkcs", 0, NULL, 3 },
+
+ /* Key management options */
+ { "create-key-pair", 0, NULL, 'C' },
+ { "pkcs", 1, NULL, 10 },
+ { "bits", 1, NULL, 11 },
+
+ { NULL, 0, NULL, 0 }
+};
+
+/* Command line option variables */
+static char *opt_server = NULL;
+static int opt_port = 0;
+static char *opt_nickname = NULL;
+static char *opt_channel = NULL;
+static char *opt_cipher = NULL;
+static char *opt_public_key = NULL;
+static char *opt_private_key = NULL;
+static char *opt_config_file = NULL;
+static int opt_no_silcrc = FALSE;
+
+static int opt_create_keypair = FALSE;
+static char *opt_pkcs = NULL;
+static int opt_bits = 0;
+
+/* Prints out the usage of silc client */
+
+void usage()
+{
+ printf("\
+Usage: silc [options]\n\
+\n\
+ Generic Options:\n\
+ -s, --server=HOST Open connection to server HOST\n\
+ -p, --port=PORT Set PORT as default port to connect\n\
+ -n, --nickname=STRING Set default nickname on startup\n\
+ -c, --channel=STRING Join channel on startup\n\
+ -r, --cipher=CIPHER Use CIPHER as default cipher in SILC\n\
+ -b, --public-key=FILE Public key used in SILC\n\
+ -k, --private-key=FILE Private key used in SILC\n\
+ -f, --config-file=FILE Alternate configuration file\n\
+ -q, --no-silcrc Don't load ~/.silcrc on startup\n\
+ -h, --help Display this help message\n\
+ -V, --version Display version\n\
+ --list-ciphers List supported ciphers\n\
+ --list-hash-funcs List supported hash functions\n\
+ --list-pkcs List supported PKCS's\n\
+\n\
+ Key Management Options:\n\
+ -C, --create-key-pair Create new public key pair\n\
+ --pkcs=PKCS Set the PKCS of the public key pair\n\
+ --bits=VALUE Set length of the public key pair\n\
+\n");
+}
+
+int main(int argc, char **argv)
+{
+ int opt, option_index = 1;
+ int ret;
+ SilcClient silc = NULL;
+ SilcClientConfig config = NULL;
+
+ if (argc > 1)
+ {
+ while ((opt =
+ getopt_long(argc, argv,
+ "s:p:n:c:b:k:f:qhVC",
+ long_opts, &option_index)) != EOF)
+ {
+ switch(opt)
+ {
+ /*
+ * Generic options
+ */
+ case 's':
+ if (optarg)
+ opt_server = strdup(optarg);
+ break;
+ case 'p':
+ if (optarg)
+ opt_port = atoi(optarg);
+ break;
+ case 'n':
+ if (optarg)
+ opt_nickname = strdup(optarg);
+ break;
+ case 'c':
+ if (optarg)
+ opt_channel = strdup(optarg);
+ break;
+ case 'r':
+ if (optarg)
+ opt_cipher = strdup(optarg);
+ break;
+ case 'b':
+ if (optarg)
+ opt_public_key = strdup(optarg);
+ break;
+ case 'k':
+ if (optarg)
+ opt_private_key = strdup(optarg);
+ break;
+ case 'f':
+ if (optarg)
+ opt_config_file = strdup(optarg);
+ break;
+ case 'q':
+ opt_no_silcrc = TRUE;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ break;
+ case 'V':
+ printf("\
+SILC Secure Internet Live Conferencing, version %s\n",
+ silc_version);
+ printf("\
+(c) 1997 - 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>\n");
+ exit(0);
+ break;
+ case 1:
+ silc_client_list_ciphers();
+ exit(0);
+ break;
+ case 2:
+ silc_client_list_hash_funcs();
+ exit(0);
+ break;
+ case 3:
+ silc_client_list_pkcs();
+ exit(0);
+ break;
+
+ /*
+ * Key management options
+ */
+ case 'C':
+ opt_create_keypair = TRUE;
+ break;
+ case 10:
+ if (optarg)
+ opt_pkcs = strdup(optarg);
+ break;
+ case 11:
+ if (optarg)
+ opt_bits = atoi(optarg);
+ break;
+
+ default:
+ exit(0);
+ break;
+ }
+ }
+ }
+
+ /* Init signals */
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGSEGV, SIG_DFL);
+ signal(SIGBUS, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ // signal(SIGINT, SIG_IGN);
+
+ /* Default configuration file */
+ if (!opt_config_file)
+ opt_config_file = strdup(SILC_CLIENT_CONFIG_FILE);
+
+ /* Read global configuration file. */
+ config = silc_client_config_alloc(opt_config_file);
+ if (config == NULL)
+ goto fail;
+
+ if (opt_create_keypair == TRUE) {
+ /* Create new key pair and exit */
+ silc_client_create_key_pair(opt_pkcs, opt_bits);
+ exit(0);
+ }
+
+ /* Read local configuration file */
+
+
+ /* Allocate new client */
+ ret = silc_client_alloc(&silc);
+ if (ret == FALSE)
+ goto fail;
+
+ /* Initialize the client */
+ silc->config = config;
+ ret = silc_client_init(silc);
+ if (ret == FALSE)
+ goto fail;
+
+ /* Run the client */
+ silc_client_run(silc);
+
+ /* Stop the client. This probably has been done already but it
+ doesn't hurt to do it here again. */
+ silc_client_stop(silc);
+ silc_client_free(silc);
+
+ exit(0);
+
+ fail:
+ if (config)
+ silc_client_config_free(config);
+ if (silc)
+ silc_client_free(silc);
+ exit(1);
+}
--- /dev/null
+/*
+
+ silc.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILC_H
+#define SILC_H
+
+/* Default client configuration file. This can be overridden at the
+ compilation time. Otherwise, use default. This can be overridden on
+ command line as well. */
+#ifndef SILC_CLIENT_CONFIG_FILE
+#define SILC_CLIENT_CONFIG_FILE "/etc/silc/silc.conf"
+#endif
+
+/* Default user configuration file. This file is searched from users'
+ home directory. This may override global configuration settings. */
+#define SILC_CLIENT_HOME_CONFIG_FILE ".silcrc"
+
+#endif
--- /dev/null
+[cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[hash]
+md5::64:16
+sha1::64:20
+
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+[connection]
+#lassi.kuo.fi.ssh.com:passwd::1333
+
+[commands]
+#/server lassi.kuo.fi.ssh.com:1333
+#/server lassi:1334
+#/server leevi:1333
--- /dev/null
+[cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[hash]
+md5::64:16
+sha1::64:20
+
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+[connection]
+#lassi.kuo.fi.ssh.com:passwd::1333
+
+[commands]
+#/server lassi:1333
+/server lassi:1334
+#/server leevi:1333
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS = silcd
+
+silcd_SOURCES = \
+ protocol.c \
+ route.c \
+ server.c \
+ idlist.c \
+ command.c \
+ command_reply.c \
+ serverconfig.c \
+ serverid.c \
+ silcd.c \
+ server_version.c
+
+LDADD = -L. -L.. -L../lib -lsilc
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
+ -I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
+ -I../includes \
+ -I../lib/silcmath/gmp-3.0.1
--- /dev/null
+/*
+
+ command.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* Server command list. */
+SilcServerCommand silc_command_list[] =
+{
+ SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(connect, CONNECT,
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(restart, RESTART,
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(close, CLOSE,
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(silcoper, SILCOPER,
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
+ SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
+
+ { NULL, 0 },
+};
+
+/* List of pending commands. */
+SilcServerCommandPending *silc_command_pending = NULL;
+
+/* Add new pending command to the list of pending commands. Currently
+ pending commands are executed from command replies, thus we can
+ execute any command after receiving some specific command reply.
+
+ The argument `reply_cmd' is the command reply from where the callback
+ function is to be called, thus, it IS NOT the command to be executed. */
+
+void silc_server_command_pending(SilcCommand reply_cmd,
+ SilcCommandCb callback,
+ void *context)
+{
+ SilcServerCommandPending *reply, *r;
+
+ reply = silc_calloc(1, sizeof(*reply));
+ reply->reply_cmd = reply_cmd;
+ reply->context = context;
+ reply->callback = callback;
+
+ if (silc_command_pending == NULL) {
+ silc_command_pending = reply;
+ return;
+ }
+
+ for (r = silc_command_pending; r; r = r->next) {
+ if (r->next == NULL) {
+ r->next = reply;
+ break;
+ }
+ }
+}
+
+/* Deletes pending command by reply command type. */
+
+void silc_server_command_pending_del(SilcCommand reply_cmd)
+{
+ SilcServerCommandPending *r, *tmp;
+
+ if (silc_command_pending) {
+ if (silc_command_pending->reply_cmd == reply_cmd) {
+ silc_free(silc_command_pending);
+ silc_command_pending = NULL;
+ return;
+ }
+
+ for (r = silc_command_pending; r; r = r->next) {
+ if (r->next && r->next->reply_cmd == reply_cmd) {
+ tmp = r->next;
+ r->next = r->next->next;
+ silc_free(tmp);
+ break;
+ }
+ }
+ }
+}
+
+/* Free's the command context allocated before executing the command */
+
+static void silc_server_command_free(SilcServerCommandContext cmd)
+{
+ if (cmd) {
+ silc_command_free_payload(cmd->payload);
+ silc_free(cmd);
+ }
+}
+
+/* Sends command status message as command reply packet. */
+
+static void
+silc_server_command_send_status_msg(SilcServerCommandContext cmd,
+ SilcCommand command,
+ SilcCommandStatus status,
+ unsigned char *msg,
+ unsigned int msg_len)
+{
+ SilcBuffer sp_buf, buffer;
+
+ SILC_LOG_DEBUG(("Sending command status %d", status));
+
+ sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
+ buffer = silc_command_encode_payload_va(command, 1,
+ sp_buf->data, sp_buf->len);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0,
+ buffer->data, buffer->len, FALSE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(sp_buf);
+}
+
+/* Sends simple status message as command reply packet */
+
+static void
+silc_server_command_send_status_reply(SilcServerCommandContext cmd,
+ SilcCommand command,
+ SilcCommandStatus status)
+{
+ SilcBuffer sp_buf, buffer;
+
+ SILC_LOG_DEBUG(("Sending command status %d", status));
+
+ sp_buf = silc_command_encode_status_payload(status, NULL, 0);
+ buffer = silc_command_encode_payload_va(command, 1,
+ sp_buf->data, sp_buf->len);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0,
+ buffer->data, buffer->len, FALSE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(sp_buf);
+}
+
+/* Server side of command WHOIS. Processes user's query and sends found
+ results as command replies back to the client. */
+
+SILC_SERVER_CMD_FUNC(whois)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ char *tmp, *nick = NULL, *server = NULL;
+ unsigned int argc, count = 0, len;
+ SilcClientList *entry;
+ SilcBuffer sp_buf, packet;
+ unsigned char *id_string;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ argc = silc_command_get_arg_num(cmd->payload);
+ if (argc < 1) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ if (argc > 2) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ goto out;
+ }
+
+ /* Get the nickname@server string and parse it. */
+ tmp = silc_command_get_first_arg(cmd->payload, NULL);
+ if (tmp) {
+ if (strchr(tmp, '@')) {
+ len = strcspn(tmp, "@");
+ nick = silc_calloc(len + 1, sizeof(char));
+ memcpy(nick, tmp, len);
+ server = silc_calloc(strlen(tmp) - len, sizeof(char));
+ memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
+ } else {
+ nick = strdup(tmp);
+ }
+ } else {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get the max count of reply messages allowed */
+ if (argc == 2) {
+ tmp = silc_command_get_next_arg(cmd->payload, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ if (nick)
+ silc_free(nick);
+ if (server)
+ silc_free(server);
+ goto out;
+ }
+ count = atoi(tmp);
+ }
+
+ /* Then, make the query from our local client list */
+ entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
+ nick, server);
+ if (!entry) {
+
+ /* If we are normal server and are connected to a router we will
+ make global query from the router. */
+ if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
+
+ goto ok;
+ }
+
+ /* If we are router then we will check our global list as well. */
+ if (cmd->server->server_type == SILC_ROUTER) {
+ entry =
+ silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
+ nick, server);
+ if (!entry) {
+ silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ tmp, strlen(tmp));
+ goto out;
+ }
+ goto ok;
+ }
+
+ silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ tmp, strlen(tmp));
+ goto out;
+ }
+
+ ok:
+ /* XXX, works only for local server info */
+
+ /* Send WHOIS reply */
+ id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+ tmp = silc_command_get_first_arg(cmd->payload, NULL),
+ sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+
+ /* XXX */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ char nh[256], uh[256];
+ SilcSocketConnection hsock;
+
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
+
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ strncat(nh, "@", 1);
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(cmd->server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ cmd->server->server_name, len);
+
+ strncat(uh, entry->username, strlen(entry->username));
+ strncat(uh, "@", 1);
+ hsock = (SilcSocketConnection)entry->connection;
+ len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
+ strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+
+ /* XXX */
+ if (entry->userinfo)
+ packet =
+ silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5,
+ sp_buf->data, sp_buf->len,
+ id_string, SILC_ID_CLIENT_LEN,
+ nh, strlen(nh),
+ uh, strlen(uh),
+ entry->userinfo,
+ strlen(entry->userinfo));
+ else
+ packet =
+ silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
+ sp_buf->data, sp_buf->len,
+ id_string, SILC_ID_CLIENT_LEN,
+ nh, strlen(nh),
+ uh, strlen(uh));
+
+ } else {
+ /* XXX */
+ packet =
+ silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
+ sp_buf->data, sp_buf->len,
+ id_string, SILC_ID_CLIENT_LEN,
+ entry->nickname, strlen(entry->nickname),
+ tmp, strlen(tmp)); /* XXX */
+ }
+ silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_free(id_string);
+ silc_buffer_free(packet);
+ silc_free(sp_buf);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+SILC_SERVER_CMD_FUNC(whowas)
+{
+}
+
+SILC_SERVER_CMD_FUNC(identify)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ char *tmp, *nick = NULL, *server = NULL;
+ unsigned int argc, count = 0, len;
+ SilcClientList *entry;
+ SilcBuffer sp_buf, packet;
+ unsigned char *id_string;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ argc = silc_command_get_arg_num(cmd->payload);
+ if (argc < 1) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ if (argc > 2) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ goto out;
+ }
+
+ /* Get the nickname@server string and parse it. */
+ tmp = silc_command_get_first_arg(cmd->payload, NULL);
+ if (tmp) {
+ if (strchr(tmp, '@')) {
+ len = strcspn(tmp, "@");
+ nick = silc_calloc(len + 1, sizeof(char));
+ memcpy(nick, tmp, len);
+ server = silc_calloc(strlen(tmp) - len, sizeof(char));
+ memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
+ } else {
+ nick = strdup(tmp);
+ }
+ } else {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get the max count of reply messages allowed */
+ if (argc == 2) {
+ tmp = silc_command_get_next_arg(cmd->payload, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ goto out;
+ }
+ count = atoi(tmp);
+ }
+
+ /* Then, make the query from our local client list */
+ entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
+ nick, cmd->server->md5hash);
+ if (!entry) {
+
+ /* If we are normal server and are connected to a router we will
+ make global query from the router. */
+ if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
+ SilcBuffer buffer = cmd->packet->buffer;
+
+ /* Forward the received IDENTIFY command to our router */
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+ silc_server_packet_forward(cmd->server, (SilcSocketConnection)
+ cmd->server->id_entry->router->connection,
+ buffer->data, buffer->len,
+ TRUE);
+ goto out;
+ }
+
+ /* If we are router then we will check our global list as well. */
+ if (cmd->server->server_type == SILC_ROUTER) {
+ entry =
+ silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
+ nick, cmd->server->md5hash);
+ if (!entry) {
+ silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ tmp, strlen(tmp));
+ goto out;
+ }
+ goto ok;
+ }
+
+ silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ tmp, strlen(tmp));
+ goto out;
+ }
+
+ ok:
+ /* Send IDENTIFY reply */
+ id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+ tmp = silc_command_get_first_arg(cmd->payload, NULL);
+ sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+ packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
+ sp_buf->data, sp_buf->len,
+ id_string, SILC_ID_CLIENT_LEN,
+ nick, strlen(nick));
+ if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
+ void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
+ silc_server_packet_send_dest(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0,
+ id, cmd->packet->src_id_type,
+ packet->data, packet->len, FALSE);
+ silc_free(id);
+ } else
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_free(id_string);
+ silc_buffer_free(packet);
+ silc_free(sp_buf);
+
+ out:
+ if (nick)
+ silc_free(nick);
+ if (server)
+ silc_free(server);
+ silc_server_command_free(cmd);
+}
+
+/* Checks string for bad characters and returns TRUE if they are found. */
+
+static int silc_server_command_bad_chars(char *nick)
+{
+ if (strchr(nick, '\\')) return TRUE;
+ if (strchr(nick, '\"')) return TRUE;
+ if (strchr(nick, '´')) return TRUE;
+ if (strchr(nick, '`')) return TRUE;
+ if (strchr(nick, '\'')) return TRUE;
+ if (strchr(nick, '*')) return TRUE;
+ if (strchr(nick, '/')) return TRUE;
+ if (strchr(nick, '@')) return TRUE;
+
+ return FALSE;
+}
+
+/* Server side of command NICK. Sets nickname for user. Setting
+ nickname causes generation of a new client ID for the client. The
+ new client ID is sent to the client after changing the nickname. */
+
+SILC_SERVER_CMD_FUNC(nick)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
+ SilcServer server = cmd->server;
+ SilcBuffer packet, sp_buf;
+ SilcClientID *new_id;
+ char *id_string;
+ char *nick;
+
+ SILC_LOG_DEBUG(("Start"));
+
+#define LCC(x) server->local_list->client_cache[(x) - 32]
+#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+
+ /* Check number of arguments */
+ if (silc_command_get_arg_num(cmd->payload) < 1) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Check nickname */
+ nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
+ if (silc_server_command_bad_chars(nick) == TRUE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_BAD_NICKNAME);
+ goto out;
+ }
+
+ /* Create new Client ID */
+ silc_id_create_client_id(cmd->server->id, cmd->server->rng,
+ cmd->server->md5hash, nick,
+ &new_id);
+
+ /* Send notify about nickname change to our router. We send the new
+ ID and ask to replace it with the old one. */
+ if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
+ silc_server_send_replace_id(server, server->id_entry->router->connection,
+ FALSE, id_entry->id,
+ SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
+ new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+
+ /* If we are router we have to distribute the new Client ID to all
+ routers in SILC. */
+ if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
+ silc_server_send_replace_id(server, server->id_entry->router->connection,
+ TRUE, id_entry->id,
+ SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
+ new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+
+ /* Remove old cache entry */
+ silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
+ LCCC(id_entry->nickname[0]),
+ SILC_ID_CLIENT, id_entry->id);
+
+ /* Free old ID */
+ if (id_entry->id) {
+ memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
+ silc_free(id_entry->id);
+ }
+
+ /* Save the nickname as this client is our local client */
+ if (id_entry->nickname)
+ silc_free(id_entry->nickname);
+
+ id_entry->nickname = strdup(nick);
+ id_entry->id = new_id;
+
+ /* Update client cache */
+ LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
+ id_entry->nickname, SILC_ID_CLIENT,
+ id_entry->id, (void *)id_entry);
+
+ /* Send the new Client ID as reply command back to client */
+ id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
+ sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+ packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2,
+ sp_buf->data, sp_buf->len,
+ id_string, SILC_ID_CLIENT_LEN);
+ silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_free(id_string);
+ silc_buffer_free(packet);
+ silc_free(sp_buf);
+
+ out:
+ silc_server_command_free(cmd);
+#undef LCC
+#undef LCCC
+}
+
+SILC_SERVER_CMD_FUNC(list)
+{
+}
+
+SILC_SERVER_CMD_FUNC(topic)
+{
+}
+
+SILC_SERVER_CMD_FUNC(invite)
+{
+}
+
+/* Quits connection to client. This gets called if client won't
+ close the connection even when it has issued QUIT command. */
+
+SILC_TASK_CALLBACK(silc_server_command_quit_cb)
+{
+ SilcServer server = (SilcServer)context;
+ SilcSocketConnection sock = server->sockets[fd];
+
+ /* Free all client specific data, such as client entry and entires
+ on channels this client may be on. */
+ silc_server_free_sock_user_data(server, sock);
+
+ /* Close the connection on our side */
+ silc_server_close_connection(server, sock);
+}
+
+/* Quits SILC session. This is the normal way to disconnect client. */
+
+SILC_SERVER_CMD_FUNC(quit)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcSocketConnection sock = cmd->sock;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* We quit the connection with little timeout */
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_command_quit_cb, server,
+ 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+
+ silc_server_command_free(cmd);
+}
+
+SILC_SERVER_CMD_FUNC(kill)
+{
+}
+
+SILC_SERVER_CMD_FUNC(info)
+{
+}
+
+SILC_SERVER_CMD_FUNC(connect)
+{
+}
+
+SILC_SERVER_CMD_FUNC(ping)
+{
+}
+
+SILC_SERVER_CMD_FUNC(oper)
+{
+}
+
+typedef struct {
+ char *channel_name;
+ char *nickname;
+ char *username;
+ char *hostname;
+ SilcChannelList *channel;
+ SilcServer server;
+} JoinInternalContext;
+
+SILC_TASK_CALLBACK(silc_server_command_join_notify)
+{
+ JoinInternalContext *ctx = (JoinInternalContext *)context;
+
+ if (ctx->channel->key && ctx->channel->key_len) {
+ silc_server_send_notify_to_channel(ctx->server, ctx->channel,
+ "%s (%s@%s) has joined channel %s",
+ ctx->nickname, ctx->username,
+ ctx->hostname, ctx->channel_name);
+ silc_free(ctx);
+ } else {
+ silc_task_register(ctx->server->timeout_queue, fd,
+ silc_server_command_join_notify, context,
+ 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ }
+}
+
+/* Server side of command JOIN. Joins client into requested channel. If
+ the channel does not exist it will be created. */
+
+SILC_SERVER_CMD_FUNC(join)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcSocketConnection sock = cmd->sock;
+ SilcBuffer buffer = cmd->packet->buffer;
+ int argc, i, tmp_len;
+ char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
+ unsigned char *passphrase;
+ SilcChannelList *channel;
+ SilcServerID *router_id;
+ SilcIDCache *id_cache;
+ SilcBuffer packet, sp_buf;
+ SilcClientList *client;
+
+ SILC_LOG_DEBUG(("Start"));
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+ /* Check number of parameters */
+ argc = silc_command_get_arg_num(cmd->payload);
+ if (argc < 1) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ if (argc > 3) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ goto out;
+ }
+
+ /* Get channel name */
+ tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+ if (silc_server_command_bad_chars(tmp) == TRUE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BAD_CHANNEL);
+ goto out;
+ }
+ channel_name = strdup(tmp);
+
+ /* Get passphrase */
+ tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
+ if (tmp) {
+ passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
+ memcpy(passphrase, tmp, tmp_len);
+ }
+
+ /* Get cipher name */
+ cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
+
+ /* See if the channel exists */
+ if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
+ channel_name, &id_cache) == FALSE) {
+ /* Channel not found */
+ id_cache = NULL;
+
+ /* If we are standalone server we don't have a router, we just create
+ the channel by ourselves. */
+ if (server->standalone) {
+ router_id = server->id;
+ channel = silc_server_new_channel(server, router_id,
+ cipher, channel_name);
+ goto join_channel;
+ }
+
+ /* No channel ID found, the channel does not exist on our server.
+ We send JOIN command to our router which will handle the joining
+ procedure (either creates the channel if it doesn't exist or
+ joins the client to it) - if we are normal server. */
+ if (server->server_type == SILC_SERVER) {
+
+ /* Forward the received JOIN command to the router */
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+ silc_server_packet_forward(server, (SilcSocketConnection)
+ server->id_entry->router->connection,
+ buffer->data, buffer->len,
+ TRUE);
+
+ /* Add the command to be pending. It will be re-executed after
+ router has replied back to us. */
+ cmd->pending = TRUE;
+ silc_server_command_pending(SILC_COMMAND_JOIN,
+ silc_server_command_join, context);
+ return;
+ }
+ }
+
+ /* If we are router and the channel does not exist we will check our
+ global list for the channel. */
+ if (!id_cache && server->server_type == SILC_ROUTER) {
+
+ /* Notify all routers about the new channel in SILC network. */
+ if (!server->standalone) {
+#if 0
+ silc_server_send_new_id(server, server->id_entry->router->connection,
+ TRUE,
+ xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
+#endif
+ }
+
+ }
+
+ channel = (SilcChannelList *)id_cache->context;
+
+ join_channel:
+
+ /* XXX must check whether the client already is on the channel */
+
+ /* Join the client to the channel */
+ i = channel->user_list_count;
+ channel->user_list = silc_realloc(channel->user_list,
+ sizeof(*channel->user_list) * (i + 1));
+ channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
+
+ /* If the JOIN request was forwarded to us we will make a bit slower
+ query to get the client pointer. Otherwise, we get the client pointer
+ real easy. */
+ if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
+ client = (SilcClientList *)sock->user_data;
+ channel->user_list[i].client = client;
+ } else {
+ void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
+ client = silc_idlist_find_client_by_id(server->local_list->clients, id);
+ channel->user_list[i].client = client;
+ silc_free(id);
+ }
+ channel->user_list_count++;
+
+ i = client->channel_count;
+ client->channel = silc_realloc(client->channel,
+ sizeof(*client->channel) * (i + 1));
+ client->channel[i] = channel;
+ client->channel_count++;
+
+ /* Notify router about new user on channel. If we are normal server
+ we send it to our router, if we are router we send it to our
+ primary route. */
+ if (!server->standalone) {
+
+ }
+
+ /* Send Channel ID to the client */
+ if (!cmd->pending) {
+ id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+ if (!channel->topic)
+ packet =
+ silc_command_encode_payload_va(SILC_COMMAND_JOIN, 3,
+ sp_buf->data, sp_buf->len,
+ channel_name, strlen(channel_name),
+ id_string, SILC_ID_CHANNEL_LEN);
+ else
+ packet =
+ silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
+ sp_buf->data, sp_buf->len,
+ channel_name, strlen(channel_name),
+ id_string, SILC_ID_CHANNEL_LEN,
+ channel->topic,
+ strlen(channel->topic));
+
+ if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
+ void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
+ silc_server_packet_send_dest(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0,
+ id, cmd->packet->src_id_type,
+ packet->data, packet->len, FALSE);
+ silc_free(id);
+ } else
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_free(sp_buf);
+ }
+
+ /* Send channel key to the client. Client cannot start transmitting
+ to the channel until we have sent the key. */
+ if (!cmd->pending) {
+ tmp_len = strlen(channel->channel_key->cipher->name);
+ packet =
+ silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
+ id_string, tmp_len,
+ channel->channel_key->cipher->name,
+ channel->key_len, channel->key);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ }
+
+ if (id_string)
+ silc_free(id_string);
+
+ /* Finally, send notify message to all clients on the channel about
+ new user on the channel. */
+ if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
+ if (!cmd->pending) {
+ silc_server_send_notify_to_channel(server, channel,
+ "%s (%s@%s) has joined channel %s",
+ client->nickname, client->username,
+ sock->hostname ? sock->hostname :
+ sock->ip, channel_name);
+ } else {
+ /* This is pending command request. Send the notify after we have
+ received the key for the channel from the router. */
+ JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->channel_name = channel_name;
+ ctx->nickname = client->nickname;
+ ctx->username = client->username;
+ ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
+ ctx->channel = channel;
+ ctx->server = server;
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_command_join_notify, ctx,
+ 0, 100000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ }
+ }
+
+ out:
+ silc_server_command_free(cmd);
+#undef LCC
+#undef LCCC
+}
+
+/* Server side of command MOTD. Sends servers current "message of the
+ day" to the client. */
+
+SILC_SERVER_CMD_FUNC(motd)
+{
+
+ SILC_LOG_DEBUG(("Start"));
+
+}
+
+SILC_SERVER_CMD_FUNC(umode)
+{
+}
+
+SILC_SERVER_CMD_FUNC(cmode)
+{
+}
+
+SILC_SERVER_CMD_FUNC(kick)
+{
+}
+
+SILC_SERVER_CMD_FUNC(restart)
+{
+}
+
+SILC_SERVER_CMD_FUNC(close)
+{
+}
+
+SILC_SERVER_CMD_FUNC(die)
+{
+}
+
+SILC_SERVER_CMD_FUNC(silcoper)
+{
+}
+
+SILC_SERVER_CMD_FUNC(leave)
+{
+}
+
+SILC_SERVER_CMD_FUNC(names)
+{
+}
--- /dev/null
+/*
+
+ servercommand.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+/*
+ Structure holding one command and pointer to its function.
+
+ SilcCommandCb cb
+
+ Callback function called when this command is executed.
+
+ SilcCommand cmd
+
+ The actual command. Defined in silccore/silccommand.h
+
+ SilcCommandFlag flags
+
+ Flags for the command. These set how command behaves on different
+ situations.
+
+*/
+typedef struct {
+ SilcCommandCb cb;
+ SilcCommand cmd;
+ SilcCommandFlag flags;
+} SilcServerCommand;
+
+/* All server commands */
+extern SilcServerCommand silc_command_list[];
+
+/* Context sent as argument to all commands */
+typedef struct {
+ SilcServer server;
+ SilcSocketConnection sock;
+ SilcCommandPayload payload;
+ SilcPacketContext *packet;
+ int pending;
+} *SilcServerCommandContext;
+
+/* Structure holding pending commands. If command is pending it will be
+ executed after command reply has been received and executed.
+ Pending commands are used in cases where the original command request
+ had to be forwarded to router. After router replies the pending
+ command is re-executed. */
+typedef struct SilcServerCommandPendingStruct {
+ SilcCommand reply_cmd;
+ void *context;
+ SilcCommandCb callback;
+
+ struct SilcServerCommandPendingStruct *next;
+} SilcServerCommandPending;
+
+/* List of pending commands */
+extern SilcServerCommandPending *silc_command_pending;
+
+/* Macros */
+
+/* Macro used for command declaration in command list structure */
+#define SILC_SERVER_CMD(func, cmd, flags) \
+{ silc_server_command_##func, SILC_COMMAND_##cmd, flags }
+
+/* Macro used to declare command functions */
+#define SILC_SERVER_CMD_FUNC(func) \
+void silc_server_command_##func(void *context)
+
+/* Macro used to execute commands */
+#define SILC_SERVER_COMMAND_EXEC(ctx) \
+do { \
+ SilcServerCommand *cmd; \
+ \
+ for (cmd = silc_command_list; cmd->cb; cmd++) \
+ if (cmd->cmd == silc_command_get(ctx->payload)) { \
+ cmd->cb(ctx); \
+ break; \
+ } \
+ \
+ if (cmd == NULL) { \
+ SILC_LOG_ERROR(("Unknown command, packet dropped")); \
+ silc_free(ctx); \
+ return; \
+ } \
+} while(0)
+
+/* Checks for pending commands */
+#define SILC_SERVER_COMMAND_CHECK_PENDING(ctx) \
+do { \
+ if (silc_command_pending) { \
+ SilcServerCommandPending *r; \
+ SilcCommand cmd; \
+ \
+ cmd = silc_command_get(payload); \
+ for (r = silc_command_pending; r; r = r->next) { \
+ if (r->reply_cmd == cmd) { \
+ ctx->context = r->context; \
+ ctx->callback = r->callback; \
+ break; \
+ } \
+ } \
+ } \
+} while(0)
+
+/* Executed pending command */
+#define SILC_SERVER_COMMAND_EXEC_PENDING(ctx, cmd) \
+do { \
+ if (ctx->callback) { \
+ (*ctx->callback)(ctx->context); \
+ silc_server_command_pending_del(cmd); \
+ } \
+} while(0)
+
+/* Prototypes */
+void silc_server_command_pending(SilcCommand reply_cmd,
+ SilcCommandCb callback,
+ void *context);
+void silc_server_command_pending_del(SilcCommand reply_cmd);
+SILC_SERVER_CMD_FUNC(whois);
+SILC_SERVER_CMD_FUNC(whowas);
+SILC_SERVER_CMD_FUNC(identify);
+SILC_SERVER_CMD_FUNC(newuser);
+SILC_SERVER_CMD_FUNC(nick);
+SILC_SERVER_CMD_FUNC(list);
+SILC_SERVER_CMD_FUNC(topic);
+SILC_SERVER_CMD_FUNC(invite);
+SILC_SERVER_CMD_FUNC(quit);
+SILC_SERVER_CMD_FUNC(kill);
+SILC_SERVER_CMD_FUNC(info);
+SILC_SERVER_CMD_FUNC(connect);
+SILC_SERVER_CMD_FUNC(ping);
+SILC_SERVER_CMD_FUNC(oper);
+SILC_SERVER_CMD_FUNC(pass);
+SILC_SERVER_CMD_FUNC(admin);
+SILC_SERVER_CMD_FUNC(join);
+SILC_SERVER_CMD_FUNC(motd);
+SILC_SERVER_CMD_FUNC(umode);
+SILC_SERVER_CMD_FUNC(cmode);
+SILC_SERVER_CMD_FUNC(kick);
+SILC_SERVER_CMD_FUNC(ignore);
+SILC_SERVER_CMD_FUNC(restart);
+SILC_SERVER_CMD_FUNC(close);
+SILC_SERVER_CMD_FUNC(die);
+SILC_SERVER_CMD_FUNC(silcoper);
+SILC_SERVER_CMD_FUNC(leave);
+SILC_SERVER_CMD_FUNC(names);
+
+#endif
--- /dev/null
+/*
+
+ command_reply.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+#include "command_reply.h"
+
+/* Server command reply list. Not all commands have reply function as
+ they are never sent as forwarded command packets by server. More
+ maybe added later if need appears. */
+SilcServerCommandReply silc_command_reply_list[] =
+{
+ SILC_SERVER_CMD_REPLY(join, JOIN),
+
+ { NULL, 0 },
+};
+
+/* Process received command reply. */
+
+void silc_server_command_reply_process(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcServerCommandReplyContext ctx;
+ SilcCommandPayload payload;
+
+ /* Get command reply payload from packet */
+ payload = silc_command_parse_payload(buffer);
+ if (!payload) {
+ /* Silently ignore bad reply packet */
+ SILC_LOG_DEBUG(("Bad command reply packet"));
+ return;
+ }
+
+ /* Allocate command reply context. This must be free'd by the
+ command reply routine receiving it. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->server = server;
+ ctx->sock = sock;
+ ctx->payload = payload;
+
+ /* Check for pending commands and mark to be exeucted */
+ SILC_SERVER_COMMAND_CHECK_PENDING(ctx);
+
+ /* Execute command reply */
+ SILC_SERVER_COMMAND_REPLY_EXEC(ctx);
+}
+
+/* Free command reply context and its internals. */
+
+void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
+{
+ if (cmd) {
+ silc_command_free_payload(cmd->payload);
+ silc_free(cmd);
+ }
+}
+
+/* Received reply for forwarded JOIN command. Router has created or joined
+ the client to the channel. We save some channel information locally
+ for future use. */
+
+SILC_SERVER_CMD_REPLY_FUNC(join)
+{
+ SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+ SilcServer server = cmd->server;
+ SilcCommandStatus status;
+ SilcChannelID *id;
+ SilcChannelList *entry;
+ unsigned int argc;
+ unsigned char *id_string;
+ char *channel_name, *tmp;
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+ SILC_LOG_DEBUG(("Start"));
+
+ tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK)
+ goto out;
+
+ /* Get channel name */
+ tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
+ if (!tmp)
+ goto out;
+
+ /* Get channel ID */
+ id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
+ if (!id_string)
+ goto out;
+
+ channel_name = strdup(tmp);
+
+ /* Add the channel to our local list. */
+ id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+ silc_idlist_add_channel(&server->local_list->channels, channel_name,
+ SILC_CHANNEL_MODE_NONE, id,
+ server->id_entry->router, NULL, &entry);
+ LCCC(channel_name[0]) = silc_idcache_add(&LCC(channel_name[0]),
+ LCCC(channel_name[0]),
+ channel_name, SILC_ID_CHANNEL,
+ (void *)id, (void *)entry);
+ entry->global_users = TRUE;
+
+ /* Execute pending JOIN command so that the client who originally
+ wanted to join the channel will be joined after all. */
+ SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
+
+ out:
+ silc_server_command_reply_free(cmd);
+#undef LCC
+#undef LCCC
+}
--- /dev/null
+/*
+
+ command_reply.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_REPLY_H
+#define COMMAND_REPLY_H
+
+/* Structure holding one command reply and pointer to its function. */
+typedef struct {
+ SilcCommandCb cb;
+ SilcCommand cmd;
+} SilcServerCommandReply;
+
+/* All server command replys */
+extern SilcServerCommandReply silc_command_reply_list[];
+
+/* Context sent as argument to all command reply functions */
+typedef struct {
+ SilcServer server;
+ SilcSocketConnection sock;
+ SilcCommandPayload payload;
+
+ /* If defined this executes the pending command. */
+ void *context;
+ SilcCommandCb callback;
+} *SilcServerCommandReplyContext;
+
+/* Macros */
+
+/* Macro used for command declaration in command reply list structure */
+#define SILC_SERVER_CMD_REPLY(func, cmd ) \
+{ silc_server_command_reply_##func, SILC_COMMAND_##cmd }
+
+/* Macro used to declare command reply functions */
+#define SILC_SERVER_CMD_REPLY_FUNC(func) \
+void silc_server_command_reply_##func(void *context)
+
+/* Macro used to execute command replies */
+#define SILC_SERVER_COMMAND_REPLY_EXEC(ctx) \
+do { \
+ SilcServerCommandReply *cmd; \
+ \
+ for (cmd = silc_command_reply_list; cmd->cb; cmd++) \
+ if (cmd->cmd == silc_command_get(ctx->payload)) { \
+ cmd->cb(ctx); \
+ break; \
+ } \
+ \
+ if (cmd == NULL) { \
+ silc_free(ctx); \
+ return; \
+ } \
+} while(0)
+
+/* Prototypes */
+void silc_server_command_reply_process(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer);
+SILC_SERVER_CMD_REPLY_FUNC(join);
+
+#endif
--- /dev/null
+/*
+
+ idlist.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "idlist.h"
+
+/* Adds a new server to the list. The pointer sent as argument is allocated
+ and returned. */
+
+void silc_idlist_add_server(SilcServerList **list,
+ char *server_name, int server_type,
+ SilcServerID *id, SilcServerList *router,
+ SilcCipher send_key, SilcCipher receive_key,
+ SilcPKCS public_key, SilcHmac hmac,
+ SilcServerList **new_idlist)
+{
+ SilcServerList *last, *idlist;
+
+ SILC_LOG_DEBUG(("Adding new server to id list"));
+
+ idlist = silc_calloc(1, sizeof(*idlist));
+ if (idlist == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new server list object"));
+ *new_idlist = NULL;
+ return;
+ }
+
+ /* Set the pointers */
+ idlist->server_name = server_name;
+ idlist->server_type = server_type;
+ idlist->id = id;
+ idlist->router = router;
+ idlist->send_key = send_key;
+ idlist->receive_key = receive_key;
+ idlist->public_key = public_key;
+ idlist->hmac = hmac;
+ idlist->next = idlist;
+ idlist->prev = idlist;
+
+ /* First on the list? */
+ if (!*list) {
+ *list = idlist;
+ *new_idlist = idlist;
+ return;
+ }
+
+ /* Add it to the list */
+ last = (*list)->prev;
+ last->next = idlist;
+ (*list)->prev = idlist;
+ idlist->next = (*list);
+ idlist->prev = last;
+
+ if (new_idlist)
+ *new_idlist = idlist;
+}
+
+/* Adds a new client to the client list. This is called when new client
+ connection is accepted to the server. This adds all the relevant data
+ about the client and session with it to the list. This list is
+ referenced for example when sending message to the client. */
+
+void silc_idlist_add_client(SilcClientList **list, char *nickname,
+ char *username, char *userinfo,
+ SilcClientID *id, SilcServerList *router,
+ SilcCipher send_key, SilcCipher receive_key,
+ SilcPKCS public_key, SilcHmac hmac,
+ SilcClientList **new_idlist)
+{
+ SilcClientList *last, *idlist;
+
+ SILC_LOG_DEBUG(("Adding new client to id list"));
+
+ idlist = silc_calloc(1, sizeof(*idlist));
+ if (idlist == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new client list object"));
+ return;
+ }
+
+ /* Set the pointers */
+ idlist->nickname = nickname;
+ idlist->username = username;
+ idlist->userinfo = userinfo;
+ idlist->id = id;
+ idlist->router = router;
+ idlist->send_key = send_key;
+ idlist->receive_key = receive_key;
+ idlist->public_key = public_key;
+ idlist->hmac = hmac;
+ idlist->next = idlist;
+ idlist->prev = idlist;
+
+ /* First on the list? */
+ if (!(*list)) {
+ *list = idlist;
+ if (new_idlist)
+ *new_idlist = idlist;
+ return;
+ }
+
+ /* Add it to the list */
+ last = (*list)->prev;
+ last->next = idlist;
+ (*list)->prev = idlist;
+ idlist->next = *list;
+ idlist->prev = last;
+
+ if (new_idlist)
+ *new_idlist = idlist;
+}
+
+/* Free client entry. This free's everything. */
+
+void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry)
+{
+ if (entry) {
+ if (entry->nickname)
+ silc_free(entry->nickname);
+ if (entry->username)
+ silc_free(entry->username);
+ if (entry->userinfo)
+ silc_free(entry->userinfo);
+ if (entry->id)
+ silc_free(entry->id);
+ if (entry->send_key)
+ silc_cipher_free(entry->send_key);
+ if (entry->receive_key)
+ silc_cipher_free(entry->receive_key);
+ if (entry->public_key)
+ silc_pkcs_free(entry->public_key);
+ if (entry->hmac)
+ silc_hmac_free(entry->hmac);
+ if (entry->hmac_key) {
+ memset(entry->hmac_key, 0, entry->hmac_key_len);
+ silc_free(entry->hmac_key);
+ }
+
+ /* Last one in list? */
+ if (*list == entry && entry->next == entry) {
+ *list = NULL;
+ silc_free(entry);
+ return;
+ }
+
+ /* At the start of list? */
+ if (*list == entry && entry->next != entry) {
+ *list = entry->next;
+ entry->next->prev = entry->prev;
+ entry->prev->next = *list;
+ silc_free(entry);
+ return;
+ }
+
+ /* Remove from list */
+ entry->prev->next = entry->next;
+ entry->next->prev = entry->prev;
+ silc_free(entry);
+ return;
+ }
+}
+
+SilcClientList *
+silc_idlist_find_client_by_nickname(SilcClientList *list,
+ char *nickname,
+ char *server)
+{
+ SilcClientList *first, *entry;
+
+ SILC_LOG_DEBUG(("Finding client by nickname"));
+
+ if (!list)
+ return NULL;
+
+ first = entry = list;
+ if (!strcmp(entry->nickname, nickname)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+ entry = entry->next;
+
+ while(entry != first) {
+ if (!strcmp(entry->nickname, nickname)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+SilcClientList *
+silc_idlist_find_client_by_hash(SilcClientList *list,
+ char *nickname, SilcHash md5hash)
+{
+ SilcClientList *first, *entry;
+ unsigned char hash[16];
+
+ SILC_LOG_DEBUG(("Finding client by nickname hash"));
+
+ if (!list)
+ return NULL;
+
+ /* Make hash of the nickname */
+ silc_hash_make(md5hash, nickname, strlen(nickname), hash);
+
+ first = entry = list;
+ if (entry && !SILC_ID_COMPARE_HASH(entry->id, hash)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+ entry = entry->next;
+
+ while(entry != first) {
+ if (entry && !SILC_ID_COMPARE_HASH(entry->id, hash)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+SilcClientList *
+silc_idlist_find_client_by_id(SilcClientList *list, SilcClientID *id)
+{
+ SilcClientList *first, *entry;
+
+ SILC_LOG_DEBUG(("Finding client by Client ID"));
+
+ if (!list)
+ return NULL;
+
+ first = entry = list;
+ if (entry && !SILC_ID_CLIENT_COMPARE(entry->id, id)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+ entry = entry->next;
+
+ while(entry != first) {
+ if (entry && !SILC_ID_CLIENT_COMPARE(entry->id, id)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+/* Adds new channel to the list. */
+
+void silc_idlist_add_channel(SilcChannelList **list,
+ char *channel_name, int mode,
+ SilcChannelID *id, SilcServerList *router,
+ SilcCipher channel_key,
+ SilcChannelList **new_idlist)
+{
+ SilcChannelList *last, *idlist;
+
+ SILC_LOG_DEBUG(("Adding new channel to id list"));
+
+ idlist = silc_calloc(1, sizeof(*idlist));
+ if (idlist == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new channel list object"));
+ return;
+ }
+
+ /* Set the pointers */
+ idlist->channel_name = channel_name;
+ idlist->mode = mode;
+ idlist->id = id;
+ idlist->router = router;
+ idlist->channel_key = channel_key;
+ idlist->next = idlist;
+ idlist->prev = idlist;
+
+ /* First on the list? */
+ if (!*list) {
+ *list = idlist;
+ if (new_idlist)
+ *new_idlist = idlist;
+ return;
+ }
+
+ /* Add it to the list */
+ last = (*list)->prev;
+ last->next = idlist;
+ (*list)->prev = idlist;
+ idlist->next = (*list);
+ idlist->prev = last;
+
+ if (new_idlist)
+ *new_idlist = idlist;
+}
+
+SilcChannelList *
+silc_idlist_find_channel_by_id(SilcChannelList *list, SilcChannelID *id)
+{
+ SilcChannelList *first, *entry;
+
+ SILC_LOG_DEBUG(("Finding channel by Channel ID"));
+
+ if (!list)
+ return NULL;
+
+ first = entry = list;
+ if (entry && !SILC_ID_CHANNEL_COMPARE(entry->id, id)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+ entry = entry->next;
+
+ while(entry != first) {
+ if (entry && !SILC_ID_CHANNEL_COMPARE(entry->id, id)) {
+ SILC_LOG_DEBUG(("Found"));
+ return entry;
+ }
+
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+/* Free channel entry. This free's everything. */
+
+void silc_idlist_del_channel(SilcChannelList **list, SilcChannelList *entry)
+{
+ if (entry) {
+ if (entry->channel_name)
+ silc_free(entry->channel_name);
+ if (entry->id)
+ silc_free(entry->id);
+ if (entry->topic)
+ silc_free(entry->topic);
+ if (entry->channel_key)
+ silc_cipher_free(entry->channel_key);
+ if (entry->key) {
+ memset(entry->key, 0, entry->key_len);
+ silc_free(entry->key);
+ }
+ memset(entry->iv, 0, sizeof(entry->iv));
+
+ if (entry->user_list_count)
+ silc_free(entry->user_list);
+
+ /* Last one in list? */
+ if (*list == entry && entry->next == entry) {
+ *list = NULL;
+ silc_free(entry);
+ return;
+ }
+
+ /* At the start of list? */
+ if (*list == entry && entry->next != entry) {
+ *list = entry->next;
+ entry->next->prev = entry->prev;
+ entry->prev->next = *list;
+ silc_free(entry);
+ return;
+ }
+
+ /* Remove from list */
+ entry->prev->next = entry->next;
+ entry->next->prev = entry->prev;
+ silc_free(entry);
+ return;
+ }
+}
--- /dev/null
+/*
+
+ idlist.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef IDLIST_H
+#define IDLIST_H
+
+/* Forward declarations */
+typedef struct SilcServerListStruct SilcServerList;
+typedef struct SilcClientListStruct SilcClientList;
+typedef struct SilcChannelListStruct SilcChannelList;
+
+/*
+ SILC Server list object.
+
+ This list holds information about servers in SILC network. However,
+ contents of this list is highly dependent of what kind of server we are
+ (normal server or router server) and whether the list is used as a local
+ list or a global list. These factors dictates the contents of this list.
+
+ This list is defined as follows:
+
+ Server type List type Contents
+ =======================================================================
+ server local list Server itself
+ server global list NULL
+ router local list All servers is the cell
+ router global list All servers in the SILC network
+
+ Following short description of the fields:
+
+ char *server_name
+
+ Logical name of the server. There is no limit of the length of the
+ server name. This is usually the same name as defined in DNS.
+
+ int server_type
+
+ Type of the server. SILC_SERVER or SILC_ROUTER are the possible
+ choices for this.
+
+ SilcServerID *id
+
+ ID of the server. This includes all the relevant information about
+ the server SILC will ever need. These are also the informations
+ that is broadcasted between servers and routers in the SILC network.
+
+ struct SilcServerListStruct *router
+
+ This is a pointer back to the server list. This is the router server
+ where this server is connected to. If this is the router itself and
+ it doesn't have a route this is NULL.
+
+ SilcCipher send_key
+
+ SilcCipher receive_key
+
+ void *connection
+
+ A pointer, usually, to the socket list for fast referencing to
+ the data used in connection with this server. This may be anything
+ but as just said, this is usually pointer to the socket connection
+ list.
+
+*/
+struct SilcServerListStruct {
+ char *server_name;
+ int server_type;
+ SilcServerID *id;
+
+ /* Pointer to the router */
+ struct SilcServerListStruct *router;
+
+ /* Keys */
+ SilcCipher send_key;
+ SilcCipher receive_key;
+ SilcPKCS public_key;
+ SilcHmac hmac;
+ unsigned char *hmac_key;
+ unsigned int hmac_key_len;
+
+ /* Connection data */
+ void *connection;
+
+ struct SilcServerListStruct *next;
+ struct SilcServerListStruct *prev;
+};
+
+/*
+ SILC Client list object.
+
+ This list holds information about connected clients ie. users in the SILC
+ network. The contents of this list is depended on whether we are normal
+ server or router server and whether the list is a local or global list.
+
+ This list is defined as follows:
+
+ Server type List type Contents
+ =======================================================================
+ server local list All clients in server
+ server global list NULL
+ router local list All clients in cell
+ router global list All clients in SILC
+
+ Following short description of the fields:
+
+ char username
+
+ Client's (meaning user's) real name. This is defined in following
+ manner:
+
+ Server type List type Contents
+ ====================================================
+ server local list User's name
+ router local list NULL
+ router global list NULL
+
+ Router doesn't hold this information since it is not vital data
+ for the router. If this information is needed by the client it is
+ fetched when it is needed.
+
+ char userinfo
+
+ Information about user. This is free information and can be virtually
+ anything. This is defined in following manner:
+
+ Server type List type Contents
+ ====================================================
+ server local list User's information
+ router local list NULL
+ router global list NULL
+
+ Router doesn't hold this information since it is not vital data
+ for the router. If this information is needed by the client it is
+ fetched when it is needed.
+
+ SilcClientID *id
+
+ ID of the client. This includes all the information SILC will ever
+ need. Notice that no nickname of the user is saved anywhere. This is
+ beacuse of SilcClientID includes 88 bit hash value of the user's
+ nickname which can be used to track down specific user by their
+ nickname. Nickname is not relevant information that would need to be
+ saved as plain.
+
+ int mode
+
+ Client's mode. Client maybe for example server operator or
+ router operator (SILC operator).
+
+ SilcServerList *router
+
+ This is a pointer to the server list. This is the router server whose
+ cell this client is coming from. This is used to route messages to
+ this client.
+
+ SilcCipher session_key
+
+ The actual session key established by key exchange protcol between
+ connecting parties. This is used for both encryption and decryption.
+
+ SilcPKCS public_key
+
+ Public key of the client. This maybe NULL.
+
+ SilcHmac hmac
+ unsigned char *hmac_key
+ unsigned int hmac_key_len
+
+ MAC key used to compute MAC's for packets.
+
+ void *connection
+
+ A pointer, usually, to the socket list for fast referencing to
+ the data used in connection with this client. This may be anything
+ but as just said, this is usually pointer to the socket connection
+ list.
+
+*/
+struct SilcClientListStruct {
+ char *nickname;
+ char *username;
+ char *userinfo;
+ SilcClientID *id;
+ int mode;
+
+ /* Pointer to the router */
+ SilcServerList *router;
+
+ /* Pointers to channels this client has joined */
+ SilcChannelList **channel;
+ unsigned int channel_count;
+
+ /* Keys */
+ SilcCipher send_key;
+ SilcCipher receive_key;
+ SilcPKCS public_key;
+ SilcHmac hmac;
+ unsigned char *hmac_key;
+ unsigned int hmac_key_len;
+
+ /* Connection data */
+ void *connection;
+
+ struct SilcClientListStruct *next;
+ struct SilcClientListStruct *prev;
+};
+
+/*
+ SILC Channel Client list structure.
+
+ This list used only by the SilcChannelList object and it holds information
+ about current clients (ie. users) on channel. Following short description
+ of the fields:
+
+ SilcClientList client
+
+ Pointer to the client list. This is the client currently on channel.
+
+ int mode
+
+ Client's current mode on the channel.
+
+*/
+typedef struct SilcChannelClientListStruct {
+ SilcClientList *client;
+ int mode;
+} SilcChannelClientList;
+
+/*
+ SILC Channel list object.
+
+ This list holds information about channels in SILC network. The contents
+ of this list is depended on whether we are normal server or router server
+ and whether the list is a local or global list.
+
+ This list is defined as follows:
+
+ Server type List type Contents
+ =======================================================================
+ server local list All channels in server
+ server global list NULL
+ router local list All channels in cell
+ router global list All channels in SILC
+
+ Following short description of the fields:
+
+ char *channel_name
+
+ Logical name of the channel.
+
+ int mode
+
+ Current mode of the channel.
+
+ SilcChannelID *id
+
+ ID of the channel. This includes all the information SILC will ever
+ need.
+
+ int global_users
+
+ Boolean value to tell whether there are users outside this server
+ on this channel. This is set to TRUE if router sends message to
+ the server that there are users outside your server on your
+ channel as well. This way server knows that messages needs to be
+ sent to the router for further routing. If this is a normal
+ server and this channel is not created on this server this field
+ is always TRUE. If this server is a router this field is ignored.
+
+ char *topic
+
+ Current topic of the channel.
+
+ SilcServerList *router
+
+ This is a pointer to the server list. This is the router server
+ whose cell this channel belongs to. This is used to route messages
+ to this channel.
+
+ SilcCipher send_key
+
+
+ SilcCipher receive_key
+
+*/
+struct SilcChannelListStruct {
+ char *channel_name;
+ int mode;
+ SilcChannelID *id;
+ int global_users;
+ char *topic;
+
+ /* List of users on channel */
+ SilcChannelClientList *user_list;
+ unsigned int user_list_count;
+
+ /* Pointer to the router */
+ SilcServerList *router;
+
+ /* Channel keys */
+ SilcCipher channel_key;
+ unsigned char *key;
+ unsigned int key_len;
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
+
+ struct SilcChannelListStruct *next;
+ struct SilcChannelListStruct *prev;
+};
+
+/*
+ SILC ID List object.
+
+ As for remainder these lists are defined as follows:
+
+ List Server type List type Contents
+ =======================================================================
+ servers server local list Server itself
+ servers server global list NULL
+ servers router local list All servers in cell
+ servers router global list All servers in SILC
+
+ clients server local list All clients in server
+ clients server global list NULL
+ clients router local list All clients in cell
+ clients router global list All clients in SILC
+
+ channels server local list All channels in server
+ channels server global list NULL
+ channels router local list All channels in cell
+ channels router global list All channels in SILC
+
+ As seen on the list normal server never defines a global list. This is
+ because of normal server don't know anything about anything global data,
+ they get it from the router if and when they need it. Routers, on the
+ other hand, always define local and global lists because routers really
+ know all the relevant data in the SILC network.
+
+*/
+typedef struct SilcIDListStruct {
+ SilcServerList *servers;
+ SilcClientList *clients;
+ SilcChannelList *channels;
+
+ /* ID Caches. Caches are used to perform fast search on the ID's. */
+ SilcIDCache *server_cache[96];
+ unsigned int server_cache_count[96];
+ SilcIDCache *client_cache[96];
+ unsigned int client_cache_count[96];
+ SilcIDCache *channel_cache[96];
+ unsigned int channel_cache_count[96];
+} SilcIDListObject;
+
+typedef SilcIDListObject *SilcIDList;
+
+/*
+ Temporary ID List object.
+
+ This is used during authentication phases where we still don't
+ know what kind of connection remote connection is, hence, we
+ will use this structure instead until we know what type of
+ connection remote end is.
+
+ This is not in any list. This is always individually allocated
+ and used as such.
+
+*/
+typedef struct {
+ SilcCipher send_key;
+ SilcCipher receive_key;
+ SilcPKCS pkcs;
+
+ SilcHmac hmac;
+ unsigned char *hmac_key;
+ unsigned int hmac_key_len;
+
+ /* SilcComp comp */
+} SilcIDListUnknown;
+
+/* Prototypes */
+void silc_idlist_add_server(SilcServerList **list,
+ char *server_name, int server_type,
+ SilcServerID *id, SilcServerList *router,
+ SilcCipher send_key, SilcCipher receive_key,
+ SilcPKCS public_key, SilcHmac hmac,
+ SilcServerList **new_idlist);
+void silc_idlist_add_client(SilcClientList **list, char *nickname,
+ char *username, char *userinfo,
+ SilcClientID *id, SilcServerList *router,
+ SilcCipher send_key, SilcCipher receive_key,
+ SilcPKCS public_key, SilcHmac hmac,
+ SilcClientList **new_idlist);
+void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry);
+SilcClientList *
+silc_idlist_find_client_by_nickname(SilcClientList *list,
+ char *nickname,
+ char *server);
+SilcClientList *
+silc_idlist_find_client_by_hash(SilcClientList *list,
+ char *nickname, SilcHash hash);
+SilcClientList *
+silc_idlist_find_client_by_id(SilcClientList *list, SilcClientID *id);
+void silc_idlist_add_channel(SilcChannelList **list,
+ char *channel_name, int mode,
+ SilcChannelID *id, SilcServerList *router,
+ SilcCipher channel_key,
+ SilcChannelList **new_idlist);
+SilcChannelList *
+silc_idlist_find_channel_by_id(SilcChannelList *list, SilcChannelID *id);
+void silc_idlist_del_channel(SilcChannelList **list, SilcChannelList *entry);
+
+#endif
--- /dev/null
+[Cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[ServerInfo]
+leevi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1333
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ListenPort]
+10.2.1.7:10.2.1.7:1333
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:leevi_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+10.2.1.199:passwd:priikone:priikone:1
+
+[ServerConnection]
+10.2.1.7:passwd:priikone:1334:1:1
+
+[RouterConnection]
+
+[DenyConnection]
+[RedirectClient]
--- /dev/null
+[Cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[ServerInfo]
+leevi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ListenPort]
+10.2.1.7:10.2.1.7:1334
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:leevi2_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+10.2.1.199:passwd:priikone:priikone:1
+
+[ServerConnection]
+
+[RouterConnection]
+10.2.1.7:passwd:priikone:1333:1:1
+
+[DenyConnection]
+[RedirectClient]
--- /dev/null
+/*
+
+ protocol.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Server side of the protocols.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+SILC_TASK_CALLBACK(silc_server_protocol_connection_auth);
+SILC_TASK_CALLBACK(silc_server_protocol_channel_auth);
+SILC_TASK_CALLBACK(silc_server_protocol_key_exchange);
+
+/* SILC client protocol list */
+const SilcProtocolObject silc_protocol_list[] =
+{
+ { SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+ silc_server_protocol_connection_auth },
+ { SILC_PROTOCOL_SERVER_CHANNEL_AUTH,
+ silc_server_protocol_channel_auth },
+ { SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ silc_server_protocol_key_exchange },
+
+ { SILC_PROTOCOL_SERVER_NONE, NULL },
+};
+
+/*
+ * Key Exhange protocol functions
+ */
+
+/* Packet sending callback. This function is provided as packet sending
+ routine to the Key Exchange functions. */
+
+static void silc_server_protocol_ke_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerKEInternalContext *ctx =
+ (SilcServerKEInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+
+ /* Send the packet immediately */
+ silc_server_packet_send(server, ske->sock,
+ type, 0, packet->data, packet->len, TRUE);
+}
+
+/* Sets the negotiated key material into use for particular connection. */
+
+static void silc_server_protocol_ke_set_keys(SilcSKE ske,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat,
+ SilcCipher cipher,
+ SilcPKCS pkcs,
+ SilcHash hash,
+ int is_responder)
+{
+ SilcIDListUnknown *conn_data;
+ SilcHash nhash;
+
+ SILC_LOG_DEBUG(("Setting new key into use"));
+
+ conn_data = silc_calloc(1, sizeof(*conn_data));
+
+ /* Allocate cipher to be used in the communication */
+ silc_cipher_alloc(cipher->cipher->name, &conn_data->send_key);
+ silc_cipher_alloc(cipher->cipher->name, &conn_data->receive_key);
+
+ if (is_responder == TRUE) {
+ conn_data->send_key->cipher->set_key(conn_data->send_key->context,
+ keymat->receive_enc_key,
+ keymat->enc_key_len);
+ conn_data->send_key->set_iv(conn_data->send_key, keymat->receive_iv);
+ conn_data->receive_key->cipher->set_key(conn_data->receive_key->context,
+ keymat->send_enc_key,
+ keymat->enc_key_len);
+ conn_data->receive_key->set_iv(conn_data->receive_key, keymat->send_iv);
+
+ } else {
+ conn_data->send_key->cipher->set_key(conn_data->send_key->context,
+ keymat->send_enc_key,
+ keymat->enc_key_len);
+ conn_data->send_key->set_iv(conn_data->send_key, keymat->send_iv);
+ conn_data->receive_key->cipher->set_key(conn_data->receive_key->context,
+ keymat->receive_enc_key,
+ keymat->enc_key_len);
+ conn_data->receive_key->set_iv(conn_data->receive_key, keymat->receive_iv);
+ }
+
+ /* Allocate PKCS to be used */
+#if 0
+ /* XXX Do we ever need to allocate PKCS for the connection??
+ If yes, we need to change KE protocol to get the initiators
+ public key. */
+ silc_pkcs_alloc(pkcs->pkcs->name, &conn_data->pkcs);
+ silc_pkcs_set_public_key(conn_data->pkcs, ske->ke2_payload->pk_data,
+ ske->ke2_payload->pk_len);
+#endif
+
+ /* Save HMAC key to be used in the communication. */
+ silc_hash_alloc(hash->hash->name, &nhash);
+ silc_hmac_alloc(nhash, &conn_data->hmac);
+ conn_data->hmac_key_len = keymat->hmac_key_len;
+ conn_data->hmac_key = silc_calloc(conn_data->hmac_key_len,
+ sizeof(unsigned char));
+ memcpy(conn_data->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
+
+ sock->user_data = (void *)conn_data;
+}
+
+/* Performs key exchange protocol. This is used for both initiator
+ and responder key exchange. This is performed always when accepting
+ new connection to the server. This may be called recursively. */
+
+SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerKEInternalContext *ctx =
+ (SilcServerKEInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSKEStatus status = 0;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ SILC_LOG_DEBUG(("State=%d", protocol->state));
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start protocol
+ */
+ SilcSKE ske;
+
+ /* Allocate Key Exchange object */
+ ske = silc_ske_alloc();
+ ctx->ske = ske;
+
+ if (ctx->responder == TRUE) {
+ /* Start the key exchange by processing the received security
+ properties packet from initiator. */
+ status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+ ctx->packet, NULL, NULL);
+ } else {
+ SilcSKEStartPayload *start_payload;
+
+ /* Assemble security properties. */
+ silc_ske_assemble_security_properties(ske, &start_payload);
+
+ /* Start the key exchange by sending our security properties
+ to the remote end. */
+ status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
+ start_payload,
+ silc_server_protocol_ke_send_packet,
+ context);
+ }
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Advance protocol state and call the next state if we are responder */
+ protocol->state++;
+ if (ctx->responder == TRUE)
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000);
+ }
+ break;
+ case 2:
+ {
+ /*
+ * Phase 1
+ */
+ if (ctx->responder == TRUE) {
+ /* Sends the selected security properties to the initiator. */
+ status =
+ silc_ske_responder_phase_1(ctx->ske,
+ ctx->ske->start_payload,
+ silc_server_protocol_ke_send_packet,
+ context);
+ } else {
+ /* Call Phase-1 function. This processes the Key Exchange Start
+ paylaod reply we just got from the responder. The callback
+ function will receive the processed payload where we will
+ save it. */
+ status =
+ silc_ske_initiator_phase_1(ctx->ske,
+ ctx->packet,
+ NULL, NULL);
+ }
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Advance protocol state and call next state if we are initiator */
+ protocol->state++;
+ if (ctx->responder == FALSE)
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000);
+ }
+ break;
+ case 3:
+ {
+ /*
+ * Phase 2
+ */
+ if (ctx->responder == TRUE) {
+ /* Process the received Key Exchange 1 Payload packet from
+ the initiator. This also creates our parts of the Diffie
+ Hellman algorithm. */
+ status =
+ silc_ske_responder_phase_2(ctx->ske, ctx->packet, NULL, NULL);
+ } else {
+ /* Call the Phase-2 function. This creates Diffie Hellman
+ key exchange parameters and sends our public part inside
+ Key Exhange 1 Payload to the responder. */
+ status =
+ silc_ske_initiator_phase_2(ctx->ske,
+ silc_server_protocol_ke_send_packet,
+ context);
+ }
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Advance protocol state and call the next state if we are responder */
+ protocol->state++;
+ if (ctx->responder == TRUE)
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000);
+ }
+ break;
+ case 4:
+ {
+ /*
+ * Finish protocol
+ */
+ if (ctx->responder == TRUE) {
+ unsigned char *pk, *prv;
+ unsigned int pk_len, prv_len;
+
+ /* Get our public key to be sent to the initiator */
+ pk = silc_pkcs_get_public_key(server->public_key, &pk_len);
+
+ /* Get out private key to sign some data. */
+ prv = silc_pkcs_get_private_key(server->public_key, &prv_len);
+
+ /* This creates the key exchange material and sends our
+ public parts to the initiator inside Key Exchange 2 Payload. */
+ status =
+ silc_ske_responder_finish(ctx->ske,
+ pk, pk_len, prv, prv_len,
+ SILC_SKE_PK_TYPE_SILC,
+ silc_server_protocol_ke_send_packet,
+ context);
+
+ memset(pk, 0, pk_len);
+ memset(prv, 0, prv_len);
+ silc_free(pk);
+ silc_free(prv);
+ } else {
+ /* Finish the protocol. This verifies the Key Exchange 2 payload
+ sent by responder. */
+ status =
+ silc_ske_initiator_finish(ctx->ske,
+ ctx->packet, NULL, NULL);
+ }
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Send Ok to the other end. We will end the protocol as responder
+ sends Ok to us when we will take the new keys into use. */
+ if (ctx->responder == FALSE)
+ silc_ske_end(ctx->ske, silc_server_protocol_ke_send_packet, context);
+
+ /* End the protocol on the next round */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+ break;
+ case SILC_PROTOCOL_STATE_END:
+ {
+ /*
+ * End protocol
+ */
+ SilcSKEKeyMaterial *keymat;
+
+ /* Send Ok to the other end if we are responder. If we are
+ initiator we have sent this already. */
+ if (ctx->responder == TRUE)
+ silc_ske_end(ctx->ske, silc_server_protocol_ke_send_packet, context);
+
+ /* Process the key material */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
+
+ /* Take the new keys into use. */
+ silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
+ ctx->ske->prop->cipher,
+ ctx->ske->prop->pkcs,
+ ctx->ske->prop->hash,
+ ctx->responder);
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* Call the final callback */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+ case SILC_PROTOCOL_STATE_ERROR:
+ /*
+ * Error occured
+ */
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+}
+
+/*
+ * Connection Authentication protocol functions
+ */
+
+/* Performs connection authentication protocol. If responder, we
+ authenticate the remote data received. If initiator, we will send
+ authentication data to the remote end. */
+
+SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerConnAuthInternalContext *ctx =
+ (SilcServerConnAuthInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ SILC_LOG_DEBUG(("State=%d", protocol->state));
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start protocol.
+ */
+
+ if (ctx->responder == TRUE) {
+ /*
+ * We are receiving party
+ */
+ unsigned short payload_len;
+ unsigned short conn_type;
+ unsigned char *auth_data;
+
+ /* Parse the received authentication data packet. The received
+ payload is Connection Auth Payload. */
+ silc_buffer_unformat(ctx->packet,
+ SILC_STR_UI_SHORT(&payload_len),
+ SILC_STR_UI_SHORT(&conn_type),
+ SILC_STR_END);
+
+ if (payload_len != ctx->packet->len) {
+ SILC_LOG_ERROR(("Bad payload in authentication packet"));
+ SILC_LOG_DEBUG(("Bad payload in authentication packet"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+ return;
+ }
+
+ payload_len -= 4;
+
+ if (conn_type < SILC_SOCKET_TYPE_CLIENT ||
+ conn_type > SILC_SOCKET_TYPE_ROUTER) {
+ SILC_LOG_ERROR(("Bad connection type %d", conn_type));
+ SILC_LOG_DEBUG(("Bad connection type %d", conn_type));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+ return;
+ }
+
+ if (payload_len > 0) {
+ /* Get authentication data */
+ silc_buffer_pull(ctx->packet, 4);
+ silc_buffer_unformat(ctx->packet,
+ SILC_STR_UI_XNSTRING_ALLOC(&auth_data,
+ payload_len),
+ SILC_STR_END);
+ } else {
+ auth_data = NULL;
+ }
+
+ /*
+ * Check the remote connection type and make sure that we have
+ * configured this connection. If we haven't allowed this connection
+ * the authentication must be failed.
+ */
+
+ SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
+
+ /* Remote end is client */
+ if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
+ SilcConfigServerSectionClientConnection *client = NULL;
+ client =
+ silc_config_server_find_client_conn(server->config,
+ ctx->sock->ip,
+ ctx->sock->port);
+ if (!client)
+ client =
+ silc_config_server_find_client_conn(server->config,
+ ctx->sock->hostname,
+ ctx->sock->port);
+
+ if (client) {
+ switch(client->auth_meth) {
+ case SILC_PROTOCOL_CONN_AUTH_NONE:
+ /* No authentication required */
+ SILC_LOG_DEBUG(("No authentication required"));
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+ /* Password authentication */
+ SILC_LOG_DEBUG(("Password authentication"));
+ if (auth_data) {
+ if (!memcmp(client->auth_data, auth_data, strlen(auth_data))) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
+ }
+ }
+
+ /* Authentication failed */
+ SILC_LOG_ERROR(("Authentication failed"));
+ SILC_LOG_DEBUG(("Authentication failed"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+ /* Public key authentication */
+ SILC_LOG_DEBUG(("Public key authentication"));
+ if (auth_data) {
+ SilcIDListUnknown *conn_data;
+ SilcPKCS pkcs;
+
+ conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
+
+ /* Load public key from file */
+ if (silc_pkcs_load_public_key(client->auth_data,
+ &pkcs) == FALSE) {
+
+ /* Authentication failed */
+ SILC_LOG_ERROR(("Authentication failed "
+ "- could not read public key file"));
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Verify hash value HASH from KE protocol */
+ if (pkcs->pkcs->verify(pkcs->context,
+ auth_data, payload_len,
+ ctx->ske->hash,
+ ctx->ske->hash_len)
+ == TRUE) {
+ silc_pkcs_free(pkcs);
+ break;
+ }
+ }
+
+ SILC_LOG_ERROR(("Authentication failed"));
+ SILC_LOG_DEBUG(("Authentication failed"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ } else {
+ SILC_LOG_DEBUG(("No configuration for remote connection"));
+ SILC_LOG_ERROR(("Remote connection not configured"));
+ SILC_LOG_ERROR(("Authentication failed"));
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ }
+
+ /* Remote end is server */
+ if (conn_type == SILC_SOCKET_TYPE_SERVER) {
+ SilcConfigServerSectionServerConnection *serv = NULL;
+ serv =
+ silc_config_server_find_server_conn(server->config,
+ ctx->sock->ip,
+ ctx->sock->port);
+ if (!serv)
+ serv =
+ silc_config_server_find_server_conn(server->config,
+ ctx->sock->hostname,
+ ctx->sock->port);
+
+ if (serv) {
+ switch(serv->auth_meth) {
+ case SILC_PROTOCOL_CONN_AUTH_NONE:
+ /* No authentication required */
+ SILC_LOG_DEBUG(("No authentication required"));
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+ /* Password authentication */
+ SILC_LOG_DEBUG(("Password authentication"));
+ if (auth_data) {
+ if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
+ }
+ }
+
+ /* Authentication failed */
+ SILC_LOG_ERROR(("Authentication failed"));
+ SILC_LOG_DEBUG(("Authentication failed"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+ /* Public key authentication */
+ SILC_LOG_DEBUG(("Public key authentication"));
+ if (auth_data) {
+ SilcIDListUnknown *conn_data;
+ SilcPKCS pkcs;
+
+ conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
+
+ /* Load public key from file */
+ if (silc_pkcs_load_public_key(serv->auth_data,
+ &pkcs) == FALSE) {
+
+ /* Authentication failed */
+ SILC_LOG_ERROR(("Authentication failed "
+ "- could not read public key file"));
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Verify hash value HASH from KE protocol */
+ if (pkcs->pkcs->verify(pkcs->context,
+ auth_data, payload_len,
+ ctx->ske->hash,
+ ctx->ske->hash_len)
+ == TRUE) {
+ silc_pkcs_free(pkcs);
+ break;
+ }
+ }
+
+ SILC_LOG_ERROR(("Authentication failed"));
+ SILC_LOG_DEBUG(("Authentication failed"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ } else {
+ SILC_LOG_DEBUG(("No configuration for remote connection"));
+ SILC_LOG_ERROR(("Remote connection not configured"));
+ SILC_LOG_ERROR(("Authentication failed"));
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ }
+
+ /* Remote end is router */
+ if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
+ SilcConfigServerSectionServerConnection *serv = NULL;
+ serv =
+ silc_config_server_find_router_conn(server->config,
+ ctx->sock->ip,
+ ctx->sock->port);
+ if (!serv)
+ serv =
+ silc_config_server_find_router_conn(server->config,
+ ctx->sock->hostname,
+ ctx->sock->port);
+
+ if (serv) {
+ switch(serv->auth_meth) {
+ case SILC_PROTOCOL_CONN_AUTH_NONE:
+ /* No authentication required */
+ SILC_LOG_DEBUG(("No authentication required"));
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+ /* Password authentication */
+ SILC_LOG_DEBUG(("Password authentication"));
+ if (auth_data) {
+ if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
+ }
+ }
+
+ /* Authentication failed */
+ SILC_LOG_ERROR(("Authentication failed"));
+ SILC_LOG_DEBUG(("Authentication failed"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+ /* Public key authentication */
+ SILC_LOG_DEBUG(("Public key authentication"));
+ if (auth_data) {
+ SilcIDListUnknown *conn_data;
+ SilcPKCS pkcs;
+
+ conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
+
+ /* Load public key from file */
+ if (silc_pkcs_load_public_key(serv->auth_data,
+ &pkcs) == FALSE) {
+
+ /* Authentication failed */
+ SILC_LOG_ERROR(("Authentication failed "
+ "- could not read public key file"));
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Verify hash value HASH from KE protocol */
+ if (pkcs->pkcs->verify(pkcs->context,
+ auth_data, payload_len,
+ ctx->ske->hash,
+ ctx->ske->hash_len)
+ == TRUE) {
+ silc_pkcs_free(pkcs);
+ break;
+ }
+ }
+
+ SILC_LOG_ERROR(("Authentication failed"));
+ SILC_LOG_DEBUG(("Authentication failed"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ } else {
+ SILC_LOG_DEBUG(("No configuration for remote connection"));
+ SILC_LOG_ERROR(("Remote connection not configured"));
+ SILC_LOG_ERROR(("Authentication failed"));
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ }
+
+ if (auth_data) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ }
+
+ /* Save connection type. This is later used to create the
+ ID for the connection. */
+ ctx->conn_type = conn_type;
+
+ /* Advance protocol state. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 0);
+
+ } else {
+ /*
+ * We are initiator. We are authenticating ourselves to a
+ * remote server. We will send the authentication data to the
+ * other end for verify.
+ */
+ SilcBuffer packet;
+ int payload_len = 0;
+ unsigned char *auth_data = NULL;
+ unsigned int auth_data_len = 0;
+
+ switch(ctx->auth_meth) {
+ case SILC_PROTOCOL_CONN_AUTH_NONE:
+ /* No authentication required */
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+ /* Password authentication */
+ if (ctx->auth_data && ctx->auth_data_len) {
+ auth_data = ctx->auth_data;
+ auth_data_len = ctx->auth_data_len;
+ break;
+ }
+
+ /* No authentication data exits. Ask interactively from user. */
+ /* XXX */
+
+ break;
+
+ case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+ /* Public key authentication */
+ /* XXX TODO */
+ break;
+ }
+
+ payload_len = 4 + auth_data_len;
+ packet = silc_buffer_alloc(payload_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(payload_len),
+ SILC_STR_UI_SHORT(server->server_type
+ == SILC_SERVER ?
+ SILC_SOCKET_TYPE_SERVER :
+ SILC_SOCKET_TYPE_ROUTER),
+ SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
+ SILC_STR_END);
+
+ /* Send the packet to server */
+ silc_server_packet_send(server, ctx->sock,
+ SILC_PACKET_CONNECTION_AUTH, 0,
+ packet->data, packet->len, TRUE);
+
+ if (auth_data) {
+ memset(auth_data, 0, auth_data_len);
+ silc_free(auth_data);
+ }
+ silc_buffer_free(packet);
+
+ /* Next state is end of protocol */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_END:
+ {
+ /*
+ * End protocol
+ */
+
+ /* Succesfully authenticated */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS,
+ 0, NULL, 0, TRUE);
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+ case SILC_PROTOCOL_STATE_ERROR:
+ {
+ /*
+ * Error
+ */
+
+ /* Authentication failed */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
+ 0, NULL, 0, TRUE);
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+}
+
+SILC_TASK_CALLBACK(silc_server_protocol_channel_auth)
+{
+}
--- /dev/null
+/*
+
+ protocol.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+/* SILC client protocol types */
+#define SILC_PROTOCOL_SERVER_NONE 0
+#define SILC_PROTOCOL_SERVER_CONNECTION_AUTH 1
+#define SILC_PROTOCOL_SERVER_CHANNEL_AUTH 2
+#define SILC_PROTOCOL_SERVER_KEY_EXCHANGE 3
+/* #define SILC_PROTOCOL_SERVER_MAX 255 */
+
+/* Internal context for Key Exchange protocol. */
+typedef struct {
+ void *server;
+ SilcSocketConnection sock;
+ SilcRng rng;
+
+ /* TRUE if we are receiveing part of the protocol */
+ int responder;
+
+ /* Destinations ID taken from authenticataed packet so that we can
+ get the destinations ID. */
+ void *dest_id;
+ SilcIdType dest_id_type;
+
+ SilcTask timeout_task;
+ SilcBuffer packet;
+ SilcSKE ske;
+} SilcServerKEInternalContext;
+
+/* Internal context for connection authentication protocol */
+typedef struct {
+ void *server;
+ SilcSocketConnection sock;
+
+ /* TRUE if we are receiving part of the protocol */
+ int responder;
+
+ /* SKE object from Key Exchange protocol. */
+ SilcSKE ske;
+
+ /* Auth method that must be used. This is resolved before this
+ connection authentication protocol is started. Used when we are
+ initiating. */
+ unsigned int auth_meth;
+
+ /* Authentication data if we alreay know it. This is filled before
+ starting the protocol if we know the authentication data. Otherwise
+ these are and remain NULL. Used when we are initiating. */
+ unsigned char *auth_data;
+ unsigned int auth_data_len;
+
+ /* Destinations ID from KE protocol context */
+ void *dest_id;
+ SilcIdType dest_id_type;
+
+ SilcTask timeout_task;
+ SilcBuffer packet;
+ unsigned short conn_type;
+} SilcServerConnAuthInternalContext;
+
+/* Prototypes */
+
+#endif
--- /dev/null
+/*
+
+ route.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Route cache routines. Server uses these to route packets to specific
+ * routes. If route entry doesn't exist for a specific destination, server
+ * uses primary route (default route).
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "route.h"
+
+/* Route cache hash table */
+SilcServerRouteTable silc_route_cache[SILC_SERVER_ROUTE_SIZE];
+
+/* Adds new route to the route cache. The argument `index' is the
+ index value generated by silc_server_route_hash. */
+
+void silc_server_route_add(unsigned int index, unsigned int dest,
+ SilcServerList *router)
+{
+ silc_route_cache[index].dest = dest;
+ silc_route_cache[index].router = router;
+}
+
+/* Checksk whether destination has a specific router. Returns the
+ router data if found, NULL otherwise. */
+
+SilcServerList *silc_server_route_check(unsigned int dest,
+ unsigned short port)
+{
+ unsigned int index;
+
+ index = silc_server_route_hash(dest, port);
+
+ if (silc_route_cache[index].router != NULL &&
+ silc_route_cache[index].dest == dest)
+ return silc_route_cache[index].router;
+
+ return NULL;
+}
--- /dev/null
+/*
+
+ route.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef ROUTE_H
+#define ROUTE_H
+
+/* Definitions */
+
+/* Size of the route cache hash table */
+#define SILC_SERVER_ROUTE_SIZE 256
+
+/*
+ SILC Server Route table
+
+ Following short description of the fields.
+
+ unsigned int dest
+
+ Destination IPv4 address. Can be used to quickly check whether
+ the found route entry is what the caller wanted.
+
+ SilcServerList *router
+
+ Pointer to the router specific data.
+
+*/
+typedef struct {
+ unsigned int dest;
+ SilcServerList *router;
+} SilcServerRouteTable;
+
+/* Route cache hash table */
+extern SilcServerRouteTable silc_route_cache[SILC_SERVER_ROUTE_SIZE];
+
+/* Macros and super macros */
+
+/* Returns route cache hash table entry index. This is IPv4 specific.
+ `port' argument may be zero (0) if it doesn't exist. This has been
+ taken from Linux kernel's route cache code. */
+extern inline
+unsigned int silc_server_route_hash(unsigned int addr,
+ unsigned short port)
+{
+ unsigned int hash;
+
+ hash = ((addr & 0xf0f0f0f0) >> 4) | ((addr & 0x0f0f0f0f) << 4);
+ hash ^= port;
+ hash ^= (hash >> 16);
+ hash ^= (hash >> 8);
+
+ return hash & 0xff;
+}
+
+/* Prototypes */
+void silc_server_route_add(unsigned int index, unsigned int dest,
+ SilcServerList *router);
+SilcServerList *silc_server_route_check(unsigned int dest,
+ unsigned short port);
+
+#endif
--- /dev/null
+/*
+
+ server.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * This is the actual SILC server than handles everything relating to
+ * servicing the SILC connections. This is also a SILC router as a router
+ * is also normal server.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_connect_to_router);
+SILC_TASK_CALLBACK(silc_server_connect_to_router_second);
+SILC_TASK_CALLBACK(silc_server_connect_to_router_final);
+SILC_TASK_CALLBACK(silc_server_accept_new_connection);
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_second);
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_final);
+SILC_TASK_CALLBACK(silc_server_packet_process);
+SILC_TASK_CALLBACK(silc_server_packet_parse);
+SILC_TASK_CALLBACK(silc_server_timeout_remote);
+
+/* XXX */
+void silc_server_packet_parse_type(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+
+static int silc_server_packet_check_mac(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer);
+static int silc_server_packet_decrypt_rest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer);
+static int silc_server_packet_decrypt_rest_special(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer);
+
+extern char server_version[];
+
+/* Allocates a new SILC server object. This has to be done before the server
+ can be used. After allocation one must call silc_server_init to initialize
+ the server. The new allocated server object is returned to the new_server
+ argument. */
+
+int silc_server_alloc(SilcServer *new_server)
+{
+ SILC_LOG_DEBUG(("Allocating new server object"));
+
+ *new_server = silc_calloc(1, sizeof(**new_server));
+ if (*new_server == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new server object"));
+ return FALSE;
+ }
+
+ /* Set default values */
+ (*new_server)->server_name = NULL;
+ (*new_server)->server_type = SILC_SERVER;
+ (*new_server)->standalone = FALSE;
+ (*new_server)->id = NULL;
+ (*new_server)->io_queue = NULL;
+ (*new_server)->timeout_queue = NULL;
+ (*new_server)->local_list = silc_calloc(1, sizeof(SilcIDListObject));
+ (*new_server)->global_list = silc_calloc(1, sizeof(SilcIDListObject));
+ (*new_server)->rng = NULL;
+ (*new_server)->md5hash = NULL;
+ (*new_server)->sha1hash = NULL;
+ /* (*new_server)->public_key = NULL;*/
+
+ return TRUE;
+}
+
+/* Free's the SILC server object. This is called at the very end before
+ the program ends. */
+
+void silc_server_free(SilcServer server)
+{
+ if (server) {
+ if (server->local_list)
+ silc_free(server->local_list);
+ if (server->global_list)
+ silc_free(server->global_list);
+ if (server->rng)
+ silc_rng_free(server->rng);
+
+ silc_math_primegen_uninit(); /* XXX */
+ silc_free(server);
+ }
+}
+
+/* Initializes the entire SILC server. This is called always before running
+ the server. This is called only once at the initialization of the program.
+ This binds the server to its listenning port. After this function returns
+ one should call silc_server_run to start the server. This returns TRUE
+ when everything is ok to run the server. Configuration file must be
+ read and parsed before calling this. */
+
+int silc_server_init(SilcServer server)
+{
+ int *sock = NULL, sock_count, i;
+ SilcServerID *id;
+ SilcServerList *id_entry;
+ SilcHashObject hash;
+
+ SILC_LOG_DEBUG(("Initializing server"));
+ assert(server);
+ assert(server->config);
+
+ /* Set log files where log message should be saved. */
+ server->config->server = server;
+ silc_config_server_setlogfiles(server->config);
+
+ /* Register all configured ciphers, PKCS and hash functions. */
+ silc_config_server_register_ciphers(server->config);
+ silc_config_server_register_pkcs(server->config);
+ silc_config_server_register_hashfuncs(server->config);
+
+ /* Initialize random number generator for the server. */
+ server->rng = silc_rng_alloc();
+ silc_rng_init(server->rng);
+ silc_math_primegen_init(); /* XXX */
+
+ /* Initialize hash functions for server to use */
+ silc_hash_alloc("md5", &server->md5hash);
+ silc_hash_alloc("sha1", &server->sha1hash);
+
+ /* Initialize none cipher */
+ silc_cipher_alloc("none", &server->none_cipher);
+
+ /* XXXXX Generate RSA key pair */
+ {
+ unsigned char *public_key;
+ unsigned char *private_key;
+ unsigned int pk_len, prv_len;
+
+ if (silc_pkcs_alloc("rsa", &server->public_key) == FALSE) {
+ SILC_LOG_ERROR(("Could not create RSA key pair"));
+ goto err0;
+ }
+
+ if (server->public_key->pkcs->init(server->public_key->context,
+ 1024, server->rng) == FALSE) {
+ SILC_LOG_ERROR(("Could not generate RSA key pair"));
+ goto err0;
+ }
+
+ public_key =
+ server->public_key->pkcs->get_public_key(server->public_key->context,
+ &pk_len);
+ private_key =
+ server->public_key->pkcs->get_private_key(server->public_key->context,
+ &prv_len);
+
+ SILC_LOG_HEXDUMP(("public key"), public_key, pk_len);
+ SILC_LOG_HEXDUMP(("private key"), private_key, prv_len);
+
+ /* XXX Save keys */
+ silc_pkcs_save_public_key(server->public_key, "pubkey.pub",
+ public_key, pk_len);
+
+ memset(public_key, 0, pk_len);
+ memset(private_key, 0, prv_len);
+ silc_free(public_key);
+ silc_free(private_key);
+ }
+
+ /* Create a listening server. Note that our server can listen on
+ multiple ports. All listeners are created here and now. */
+ /* XXX Still check this whether to use server_info or listen_port. */
+ sock_count = 0;
+ while(server->config->listen_port) {
+ int tmp;
+
+ tmp = silc_net_create_server(server->config->listen_port->port,
+ server->config->listen_port->host);
+ if (tmp < 0)
+ goto err0;
+
+ sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
+ sock[sock_count] = tmp;
+ server->config->listen_port = server->config->listen_port->next;
+ sock_count++;
+ }
+
+ /* Allocate the entire socket list that is used in server. Eventually
+ all connections will have entry in this table (it is a table of
+ pointers to the actual object that is allocated individually
+ later). */
+ server->sockets = silc_calloc(SILC_SERVER_MAX_CONNECTIONS,
+ sizeof(*server->sockets));
+
+ for (i = 0; i < sock_count; i++) {
+ SilcSocketConnection newsocket = NULL;
+
+ /* Set socket to non-blocking mode */
+ silc_net_set_socket_nonblock(sock[i]);
+ server->sock = sock[i];
+
+ /* Create a Server ID for the server. */
+ silc_id_create_server_id(sock[i], server->rng, &id);
+ if (!id) {
+ goto err0;
+ }
+
+ server->id = id;
+ server->id_type = SILC_ID_SERVER;
+ server->server_name = server->config->server_info->server_name;
+
+ /* Add ourselves to the server list. We don't have a router yet
+ beacuse we haven't established a route yet. It will be done later.
+ For now, NULL is sent as router. This allocates new entry to
+ the ID list. */
+ silc_idlist_add_server(&server->local_list->servers,
+ server->config->server_info->server_name,
+ server->server_type, server->id, NULL,
+ server->send_key, server->receive_key,
+ NULL, NULL, &id_entry);
+ if (!id_entry)
+ goto err0;
+
+ /* Add ourselves also to the socket table. The entry allocated above
+ is sent as argument for fast referencing in the future. */
+ silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, id_entry,
+ &newsocket);
+ if (!newsocket)
+ goto err0;
+
+ server->sockets[sock[i]] = newsocket;
+
+ /* Put the allocated socket pointer also to the entry allocated above
+ for fast back-referencing to the socket list. */
+ id_entry->connection = (void *)server->sockets[sock[i]];
+ server->id_entry = id_entry;
+ }
+
+ /* Register the task queues. In SILC we have by default three task queues.
+ One task queue for non-timeout tasks which perform different kind of
+ I/O on file descriptors, timeout task queue for timeout tasks, and,
+ generic non-timeout task queue whose tasks apply to all connections. */
+ silc_task_queue_alloc(&server->io_queue, TRUE);
+ if (!server->io_queue) {
+ goto err0;
+ }
+ silc_task_queue_alloc(&server->timeout_queue, TRUE);
+ if (!server->timeout_queue) {
+ goto err1;
+ }
+ silc_task_queue_alloc(&server->generic_queue, TRUE);
+ if (!server->generic_queue) {
+ goto err1;
+ }
+
+ /* Initialize the scheduler */
+ silc_schedule_init(server->io_queue, server->timeout_queue,
+ server->generic_queue,
+ SILC_SERVER_MAX_CONNECTIONS);
+
+ /* Add the first task to the queue. This is task that is executed by
+ timeout. It expires as soon as the caller calls silc_server_run. This
+ task performs authentication protocol and key exchange with our
+ primary router. */
+ if (silc_task_register(server->timeout_queue, sock[0],
+ silc_server_connect_to_router,
+ (void *)server, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL) == NULL) {
+ goto err2;
+ }
+
+ /* If server connections has been configured then we must be router as
+ normal server cannot have server connections, only router connections. */
+ if (server->config->servers)
+ server->server_type = SILC_ROUTER;
+
+ SILC_LOG_DEBUG(("Server initialized"));
+
+ /* We are done here, return succesfully */
+ return TRUE;
+
+ err2:
+ silc_task_queue_free(server->timeout_queue);
+ err1:
+ silc_task_queue_free(server->io_queue);
+ err0:
+ for (i = 0; i < sock_count; i++)
+ silc_net_close_server(sock[i]);
+
+ return FALSE;
+}
+
+/* Stops the SILC server. This function is used to shutdown the server.
+ This is usually called after the scheduler has returned. After stopping
+ the server one should call silc_server_free. */
+
+void silc_server_stop(SilcServer server)
+{
+ SILC_LOG_DEBUG(("Stopping server"));
+
+ /* Stop the scheduler, although it might be already stopped. This
+ doesn't hurt anyone. This removes all the tasks and task queues,
+ as well. */
+ silc_schedule_stop();
+ silc_schedule_uninit();
+
+ SILC_LOG_DEBUG(("Server stopped"));
+}
+
+/* The heart of the server. This runs the scheduler thus runs the server. */
+
+void silc_server_run(SilcServer server)
+{
+ SILC_LOG_DEBUG(("Running server"));
+
+ /* Start the scheduler, the heart of the SILC server. When this returns
+ the program will be terminated. */
+ silc_schedule();
+}
+
+/* This function connects to our primary router or if we are a router this
+ establishes all our primary routes. This is called at the start of the
+ server to do authentication and key exchange with our router - called
+ from schedule. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router)
+{
+ SilcServer server = (SilcServer)context;
+ SilcSocketConnection newsocket;
+ int sock;
+
+ SILC_LOG_DEBUG(("Connecting to router(s)"));
+
+ /* if we are normal SILC server we need to connect to our cell's
+ router. */
+ if (server->server_type == SILC_SERVER) {
+ SilcProtocol protocol;
+ SilcServerKEInternalContext *proto_ctx;
+
+ /* Create connection to the router, if configured. */
+ if (server->config->routers) {
+ sock = silc_net_create_connection(server->config->routers->port,
+ server->config->routers->host);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Could not connect to router"));
+ silc_schedule_stop();
+ return;
+ }
+
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ /* Create socket connection for the connection. Even though we
+ know that we are connecting to a router we will mark the socket
+ to be unknown connection until we have executed authentication
+ protocol. */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+ server->sockets[sock] = newsocket;
+ newsocket->hostname = server->config->routers->host;
+ newsocket->port = server->config->routers->port;
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = context;
+ proto_ctx->sock = newsocket;
+ proto_ctx->rng = server->rng;
+ proto_ctx->responder = FALSE;
+
+ /* Perform key exchange protocol. silc_server_connect_to_router_second
+ will be called after the protocol is finished. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ &protocol, proto_ctx,
+ silc_server_connect_to_router_second);
+ newsocket->protocol = protocol;
+
+ /* Register a timeout task that will be executed if the protocol
+ is not executed within 15 seconds. For now, this is a hard coded
+ limit. After 15 secs the connection will be closed if the key
+ exchange protocol has not been executed. */
+ proto_ctx->timeout_task =
+ silc_task_register(server->timeout_queue, sock,
+ silc_server_timeout_remote,
+ context, 15, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as
+ well. However, this doesn't set the scheduler for outgoing traffic,
+ it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ SILC_REGISTER_CONNECTION_FOR_IO(sock);
+
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+ return;
+ }
+ }
+
+ /* if we are a SILC router we need to establish all of our primary
+ routes. */
+ if (server->server_type == SILC_ROUTER) {
+ SilcConfigServerSectionServerConnection *ptr;
+
+ /* Create the connections to all our routes */
+ ptr = server->config->routers;
+ while (ptr) {
+ SilcProtocol protocol;
+ SilcServerKEInternalContext *proto_ctx;
+
+ /* Create the connection to the remote end */
+ sock = silc_net_create_connection(ptr->port, ptr->host);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Could not connect to router"));
+ silc_schedule_stop();
+ return;
+ }
+
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ /* Create socket connection for the connection. Even though we
+ know that we are connecting to a router we will mark the socket
+ to be unknown connection until we have executed authentication
+ protocol. */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+ server->sockets[sock] = newsocket;
+ newsocket->hostname = ptr->host;
+ newsocket->port = ptr->port;
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = context;
+ proto_ctx->sock = newsocket;
+ proto_ctx->rng = server->rng;
+ proto_ctx->responder = FALSE;
+
+ /* Perform key exchange protocol. silc_server_connect_to_router_final
+ will be called after the protocol is finished. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ &protocol, proto_ctx,
+ silc_server_connect_to_router_second);
+ newsocket->protocol = protocol;
+
+ /* Register a timeout task that will be executed if the protocol
+ is not executed within 15 seconds. For now, this is a hard coded
+ limit. After 15 secs the connection will be closed if the key
+ exchange protocol has not been executed. */
+ proto_ctx->timeout_task =
+ silc_task_register(server->timeout_queue, sock,
+ silc_server_timeout_remote,
+ context, 15, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as
+ well. However, this doesn't set the scheduler for outgoing traffic,
+ it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ SILC_REGISTER_CONNECTION_FOR_IO(sock);
+
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+
+ if (!ptr->next)
+ return;
+
+ ptr = ptr->next;
+ }
+ }
+
+ SILC_LOG_DEBUG(("No router(s), server will be standalone"));
+
+ /* There wasn't a configured router, we will continue but we don't
+ have a connection to outside world. We will be standalone server. */
+ server->standalone = TRUE;
+
+ /* Add a task to the queue. This task receives new connections to the
+ server. This task remains on the queue until the end of the program. */
+ if (silc_task_register(server->io_queue, fd,
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL) == NULL) {
+ silc_schedule_stop();
+ return;
+ }
+}
+
+/* Second part of connecting to router(s). Key exchange protocol has been
+ executed and now we will execute authentication protocol. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerKEInternalContext *ctx =
+ (SilcServerKEInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSocketConnection sock = NULL;
+ SilcServerConnAuthInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ /* Error occured during protocol */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_free(ctx);
+ sock->protocol = NULL;
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Key exchange failed");
+ return;
+ }
+
+ /* Allocate internal context for the authentication protocol. This
+ is sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->sock = sock = server->sockets[fd];
+ proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
+ proto_ctx->dest_id_type = ctx->dest_id_type;
+ proto_ctx->dest_id = ctx->dest_id;
+
+ /* Resolve the authentication method used in this connection */
+ proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+ if (server->config->routers) {
+ SilcConfigServerSectionServerConnection *conn = NULL;
+
+ /* Check if we find a match from user configured connections */
+ conn = silc_config_server_find_router_conn(server->config,
+ sock->hostname,
+ sock->port);
+ if (conn) {
+ /* Match found. Use the configured authentication method */
+ proto_ctx->auth_meth = conn->auth_meth;
+ if (conn->auth_data) {
+ proto_ctx->auth_data = strdup(conn->auth_data);
+ proto_ctx->auth_data_len = strlen(conn->auth_data);
+ }
+ } else {
+ /* No match found. */
+ /* XXX */
+ }
+ } else {
+ /* XXX */
+ }
+
+ /* Free old protocol as it is finished now */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ silc_free(ctx);
+ sock->protocol = NULL;
+
+ /* Allocate the authentication protocol. This is allocated here
+ but we won't start it yet. We will be receiving party of this
+ protocol thus we will wait that connecting party will make
+ their first move. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+ &sock->protocol, proto_ctx,
+ silc_server_connect_to_router_final);
+
+ /* Register timeout task. If the protocol is not executed inside
+ this timelimit the connection will be terminated. Currently
+ this is 15 seconds and is hard coded limit (XXX). */
+ proto_ctx->timeout_task =
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_timeout_remote,
+ (void *)server, 15, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
+ /* Run the protocol */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+}
+
+/* Finalizes the connection to router. Registers a server task to the
+ queue so that we can accept new connections. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerConnAuthInternalContext *ctx =
+ (SilcServerConnAuthInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSocketConnection sock = ctx->sock;
+ SilcServerList *id_entry;
+ SilcIDListUnknown *conn_data;
+ SilcBuffer packet;
+ unsigned char *id_string;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ /* Error occured during protocol */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_free(ctx);
+ sock->protocol = NULL;
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Authentication failed");
+ return;
+ }
+
+ /* Add a task to the queue. This task receives new connections to the
+ server. This task remains on the queue until the end of the program. */
+ if (!server->listenning) {
+ if (silc_task_register(server->io_queue, server->sock,
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL) == NULL) {
+ silc_schedule_stop();
+ return;
+ } else {
+ server->listenning = TRUE;
+ }
+ }
+
+ /* Send NEW_SERVER packet to the router. We will become registered
+ to the SILC network after sending this packet. */
+ id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packet = silc_buffer_alloc(2 + 2 + SILC_ID_SERVER_LEN +
+ strlen(server->server_name));
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(SILC_ID_SERVER_LEN),
+ SILC_STR_UI_XNSTRING(id_string, SILC_ID_SERVER_LEN),
+ SILC_STR_UI_SHORT(strlen(server->server_name)),
+ SILC_STR_UI_XNSTRING(server->server_name,
+ strlen(server->server_name)),
+ SILC_STR_END);
+
+ /* Send the packet */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_NEW_SERVER, 0,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ silc_free(id_string);
+
+ SILC_LOG_DEBUG(("Connected to router %s", sock->hostname));
+
+ /* Add the connected router to local server list */
+ server->standalone = FALSE;
+ conn_data = (SilcIDListUnknown *)sock->user_data;
+ silc_idlist_add_server(&server->local_list->servers,
+ sock->hostname ? sock->hostname : sock->ip,
+ SILC_ROUTER, ctx->dest_id, NULL,
+ conn_data->send_key, conn_data->receive_key,
+ conn_data->pkcs, conn_data->hmac, &id_entry);
+
+ id_entry->hmac_key = conn_data->hmac_key;
+ id_entry->hmac_key_len = conn_data->hmac_key_len;
+ id_entry->connection = sock;
+ sock->user_data = (void *)id_entry;
+ sock->type = SILC_SOCKET_TYPE_ROUTER;
+ server->id_entry->router = id_entry;
+
+ /* Free the temporary connection data context from key exchange */
+ silc_free(conn_data);
+
+ /* Free the protocol object */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ sock->protocol = NULL;
+}
+
+/* Accepts new connections to the server. Accepting new connections are
+ done in three parts to make it async. */
+
+SILC_TASK_CALLBACK(silc_server_accept_new_connection)
+{
+ SilcServer server = (SilcServer)context;
+ SilcSocketConnection newsocket;
+ SilcServerKEInternalContext *proto_ctx;
+ int sock;
+
+ SILC_LOG_DEBUG(("Accepting new connection"));
+
+ sock = silc_net_accept_connection(server->sock);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
+ return;
+ }
+
+ /* Check max connections */
+ if (sock > SILC_SERVER_MAX_CONNECTIONS) {
+ if (server->config->redirect) {
+ /* XXX Redirecting connection to somewhere else now?? */
+ /*silc_server_send_notify("Server is full, trying to redirect..."); */
+ } else {
+ SILC_LOG_ERROR(("Refusing connection, server is full"));
+ }
+ return;
+ }
+
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ /* We don't create a ID yet, since we don't know what type of connection
+ this is yet. But, we do add the connection to the socket table. */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+ server->sockets[sock] = newsocket;
+
+ /* XXX This MUST be done async as this will block the entire server
+ process. Either we have to do our own resolver stuff or in the future
+ we can use threads. */
+ /* Perform mandatory name and address lookups for the remote host. */
+ silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
+ if (!newsocket->ip || !newsocket->hostname) {
+ SILC_LOG_DEBUG(("IP lookup/DNS lookup failed"));
+ SILC_LOG_ERROR(("IP lookup/DNS lookup failed"));
+ return;
+ }
+
+ /* Allocate internal context for key exchange protocol. This is
+ sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = context;
+ proto_ctx->sock = newsocket;
+ proto_ctx->rng = server->rng;
+ proto_ctx->responder = TRUE;
+
+ /* Prepare the connection for key exchange protocol. We allocate the
+ protocol but will not start it yet. The connector will be the
+ initiator of the protocol thus we will wait for initiation from
+ there before we start the protocol. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ &newsocket->protocol, proto_ctx,
+ silc_server_accept_new_connection_second);
+
+ /* Register a timeout task that will be executed if the connector
+ will not start the key exchange protocol within 15 seconds. For
+ now, this is a hard coded limit. After 15 secs the connection will
+ be closed if the key exchange protocol has not been started. */
+ proto_ctx->timeout_task =
+ silc_task_register(server->timeout_queue, newsocket->sock,
+ silc_server_timeout_remote,
+ context, 15, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it
+ will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ SILC_REGISTER_CONNECTION_FOR_IO(sock);
+}
+
+/* Second part of accepting new connection. Key exchange protocol has been
+ performed and now it is time to do little connection authentication
+ protocol to figure out whether this connection is client or server
+ and whether it has right to access this server (especially server
+ connections needs to be authenticated). */
+
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerKEInternalContext *ctx =
+ (SilcServerKEInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSocketConnection sock = NULL;
+ SilcServerConnAuthInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ /* Error occured during protocol */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_free(ctx);
+ sock->protocol = NULL;
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Key exchange failed");
+ return;
+ }
+
+ /* Allocate internal context for the authentication protocol. This
+ is sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->sock = sock = server->sockets[fd];
+ proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
+ proto_ctx->responder = TRUE;
+ proto_ctx->dest_id_type = ctx->dest_id_type;
+ proto_ctx->dest_id = ctx->dest_id;
+
+ /* Free old protocol as it is finished now */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ silc_free(ctx);
+ sock->protocol = NULL;
+
+ /* Allocate the authentication protocol. This is allocated here
+ but we won't start it yet. We will be receiving party of this
+ protocol thus we will wait that connecting party will make
+ their first move. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+ &sock->protocol, proto_ctx,
+ silc_server_accept_new_connection_final);
+
+ /* Register timeout task. If the protocol is not executed inside
+ this timelimit the connection will be terminated. Currently
+ this is 60 seconds and is hard coded limit (XXX). */
+ proto_ctx->timeout_task =
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_timeout_remote,
+ (void *)server, 60, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+}
+
+/* Final part of accepting new connection. The connection has now
+ been authenticated and keys has been exchanged. We also know whether
+ this is client or server connection. */
+
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerConnAuthInternalContext *ctx =
+ (SilcServerConnAuthInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSocketConnection sock = ctx->sock;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ /* Error occured during protocol */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_free(ctx);
+ sock->protocol = NULL;
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Authentication failed");
+ return;
+ }
+
+ sock->type = ctx->conn_type;
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ {
+ SilcClientList *id_entry = NULL;
+ SilcIDListUnknown *conn_data = sock->user_data;
+
+ SILC_LOG_DEBUG(("Remote host is client"));
+
+ /* Add the client to the client ID list. We have not created the
+ client ID for the client yet. This is done when client registers
+ itself by sending NEW_CLIENT packet. */
+ silc_idlist_add_client(&server->local_list->clients,
+ NULL, NULL, NULL, NULL, NULL,
+ conn_data->send_key, conn_data->receive_key,
+ conn_data->pkcs, conn_data->hmac, &id_entry);
+
+ id_entry->hmac_key = conn_data->hmac_key;
+ id_entry->hmac_key_len = conn_data->hmac_key_len;
+ id_entry->connection = sock;
+
+ /* Free the temporary connection data context from key exchange */
+ silc_free(conn_data);
+
+ /* Mark the entry to the ID list to the socket connection for
+ fast referencing in the future. */
+ sock->user_data = (void *)id_entry;
+ break;
+ }
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ {
+ SilcServerList *id_entry;
+ SilcIDListUnknown *conn_data = sock->user_data;
+
+ SILC_LOG_DEBUG(("Remote host is %s",
+ sock->type == SILC_SOCKET_TYPE_SERVER ?
+ "server" : "router"));
+
+ /* Add the server to the ID list. We don't have the server's ID
+ yet but we will receive it after the server sends NEW_SERVER
+ packet to us. */
+ silc_idlist_add_server(&server->local_list->servers, NULL,
+ sock->type == SILC_SOCKET_TYPE_SERVER ?
+ SILC_SERVER : SILC_ROUTER, NULL, NULL,
+ conn_data->send_key, conn_data->receive_key,
+ conn_data->pkcs, conn_data->hmac, &id_entry);
+
+ id_entry->hmac_key = conn_data->hmac_key;
+ id_entry->hmac_key_len = conn_data->hmac_key_len;
+ id_entry->connection = sock;
+
+ /* Free the temporary connection data context from key exchange */
+ silc_free(conn_data);
+
+ /* Mark the entry to the ID list to the socket connection for
+ fast referencing in the future. */
+ sock->user_data = (void *)id_entry;
+
+ /* There is connection to other server now, if it is router then
+ we will have connection to outside world. If we are router but
+ normal server connected to us then we will remain standalone,
+ if we are standlone. */
+ if (server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ SILC_LOG_DEBUG(("We are not standalone server anymore"));
+ server->standalone = FALSE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Connection has been fully established now. Everything is ok. */
+ SILC_LOG_DEBUG(("New connection authenticated"));
+
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_buffer_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_free(ctx);
+ sock->protocol = NULL;
+}
+
+typedef struct {
+ SilcPacketContext *packetdata;
+ SilcServer server;
+ SilcSocketConnection sock;
+ SilcCipher cipher;
+ SilcHmac hmac;
+} SilcServerInternalPacket;
+
+/* This function is used to read packets from network and send packets to
+ network. This is usually a generic task. */
+
+SILC_TASK_CALLBACK(silc_server_packet_process)
+{
+ SilcServer server = (SilcServer)context;
+ SilcSocketConnection sock = server->sockets[fd];
+ int ret, packetlen, paddedlen;
+
+ SILC_LOG_DEBUG(("Processing packet"));
+
+ /* Packet sending */
+ if (type == SILC_TASK_WRITE) {
+ SILC_LOG_DEBUG(("Writing data to connection"));
+
+ if (sock->outbuf->data - sock->outbuf->head)
+ silc_buffer_push(sock->outbuf,
+ sock->outbuf->data - sock->outbuf->head);
+
+ /* Write the packet out to the connection */
+ ret = silc_packet_write(fd, sock->outbuf);
+
+ /* If returned -2 could not write to connection now, will do
+ it later. */
+ if (ret == -2)
+ return;
+
+ /* Error */
+ if (ret == -1)
+ SILC_LOG_ERROR(("Could not write, packet dropped"));
+
+ /* The packet has been sent and now it is time to set the connection
+ back to only for input. When there is again some outgoing data
+ available for this connection it will be set for output as well.
+ This call clears the output setting and sets it only for input. */
+ SILC_SET_CONNECTION_FOR_INPUT(fd);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+
+ silc_buffer_clear(sock->outbuf);
+ return;
+ }
+
+ /* Packet receiving */
+ if (type == SILC_TASK_READ) {
+ SILC_LOG_DEBUG(("Reading data from connection"));
+
+ /* Allocate the incoming data buffer if not done already. */
+ if (!sock->inbuf)
+ sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+
+ /* Read some data from connection */
+ ret = silc_packet_read(fd, sock->inbuf);
+
+ /* If returned -2 data was not available now, will read it later. */
+ if (ret == -2)
+ return;
+
+ /* Error */
+ if (ret == -1) {
+ SILC_LOG_ERROR(("Could not read, packet dropped"));
+ return;
+ }
+
+ /* EOF */
+ if (ret == 0) {
+ SILC_LOG_DEBUG(("Read EOF"));
+
+ /* If connection is disconnecting already we will finally
+ close the connection */
+ if (SILC_IS_DISCONNECTING(sock)) {
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock);
+ silc_server_close_connection(server, sock);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock);
+ silc_server_close_connection(server, sock);
+ return;
+ }
+
+ /* If connection is disconnecting or disconnected we will ignore
+ what we read. */
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+ SILC_LOG_DEBUG(("Ignoring read data from invalid connection"));
+ return;
+ }
+
+ /* Check whether we received a whole packet. If reading went without
+ errors we either read a whole packet or the read packet is
+ incorrect and will be dropped. */
+ SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+ if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
+ SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+ silc_buffer_clear(sock->inbuf);
+ silc_server_disconnect_remote(server, sock, "Incorrect packet");
+ return;
+ }
+
+ /* Decrypt a packet coming from client. */
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ SilcClientList *clnt = (SilcClientList *)sock->user_data;
+ SilcServerInternalPacket *packet;
+ int mac_len = 0;
+
+ if (clnt->hmac)
+ mac_len = clnt->hmac->hash->hash->hash_len;
+
+ if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
+ /* Received possibly many packets at once */
+
+ while(sock->inbuf->len > 0) {
+ SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+ if (sock->inbuf->len < paddedlen) {
+ SILC_LOG_DEBUG(("Receive incorrect packet, dropped"));
+ return;
+ }
+
+ paddedlen += 2;
+ packet = silc_calloc(1, sizeof(*packet));
+ packet->server = server;
+ packet->sock = sock;
+ packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+ packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
+ silc_buffer_pull_tail(packet->packetdata->buffer,
+ SILC_BUFFER_END(packet->packetdata->buffer));
+ silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data,
+ paddedlen + mac_len);
+ if (clnt) {
+ packet->cipher = clnt->receive_key;
+ packet->hmac = clnt->hmac;
+ }
+
+ SILC_LOG_HEXDUMP(("Incoming packet, len %d",
+ packet->packetdata->buffer->len),
+ packet->packetdata->buffer->data,
+ packet->packetdata->buffer->len);
+
+ /* Parse the packet with timeout */
+ silc_task_register(server->timeout_queue, fd,
+ silc_server_packet_parse,
+ (void *)packet, 0, 100000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+
+ /* Pull the packet from inbuf thus we'll get the next one
+ in the inbuf. */
+ silc_buffer_pull(sock->inbuf, paddedlen);
+ if (clnt->hmac)
+ silc_buffer_pull(sock->inbuf, mac_len);
+ }
+ silc_buffer_clear(sock->inbuf);
+ return;
+ } else {
+ SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
+ sock->inbuf->data, sock->inbuf->len);
+
+ SILC_LOG_DEBUG(("Packet from client, length %d", paddedlen));
+
+ packet = silc_calloc(1, sizeof(*packet));
+ packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+ packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+ packet->server = server;
+ packet->sock = sock;
+ if (clnt) {
+ packet->cipher = clnt->receive_key;
+ packet->hmac = clnt->hmac;
+ }
+ silc_buffer_clear(sock->inbuf);
+
+ /* The packet is ready to be parsed now. However, this is a client
+ connection so we will parse the packet with timeout. */
+ silc_task_register(server->timeout_queue, fd,
+ silc_server_packet_parse,
+ (void *)packet, 0, 100000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+ }
+
+ /* Decrypt a packet coming from server connection */
+ if (sock->type == SILC_SOCKET_TYPE_SERVER ||
+ sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ SilcServerList *srvr = (SilcServerList *)sock->user_data;
+ SilcServerInternalPacket *packet;
+ int mac_len = 0;
+
+ if (srvr->hmac)
+ mac_len = srvr->hmac->hash->hash->hash_len;
+
+ if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
+ /* Received possibly many packets at once */
+
+ while(sock->inbuf->len > 0) {
+ SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+ if (sock->inbuf->len < paddedlen) {
+ SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+ return;
+ }
+
+ paddedlen += 2;
+ packet = silc_calloc(1, sizeof(*packet));
+ packet->server = server;
+ packet->sock = sock;
+ packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+ packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
+ silc_buffer_pull_tail(packet->packetdata->buffer,
+ SILC_BUFFER_END(packet->packetdata->buffer));
+ silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data,
+ paddedlen + mac_len);
+ if (srvr) {
+ packet->cipher = srvr->receive_key;
+ packet->hmac = srvr->hmac;
+ }
+
+ SILC_LOG_HEXDUMP(("Incoming packet, len %d",
+ packet->packetdata->buffer->len),
+ packet->packetdata->buffer->data,
+ packet->packetdata->buffer->len);
+
+ SILC_LOG_DEBUG(("Packet from %s %s, packet length %d",
+ srvr->server_type == SILC_SERVER ?
+ "server" : "router",
+ srvr->server_name, paddedlen));
+
+ /* Parse it real soon as the packet is from server. */
+ silc_task_register(server->timeout_queue, fd,
+ silc_server_packet_parse,
+ (void *)packet, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+
+ /* Pull the packet from inbuf thus we'll get the next one
+ in the inbuf. */
+ silc_buffer_pull(sock->inbuf, paddedlen);
+ if (srvr->hmac)
+ silc_buffer_pull(sock->inbuf, mac_len);
+ }
+ silc_buffer_clear(sock->inbuf);
+ return;
+ } else {
+
+ SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
+ sock->inbuf->data, sock->inbuf->len);
+
+ SILC_LOG_DEBUG(("Packet from %s %s, packet length %d",
+ srvr->server_type == SILC_SERVER ?
+ "server" : "router",
+ srvr->server_name, paddedlen));
+
+ packet = silc_calloc(1, sizeof(*packet));
+ packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+ packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+ packet->server = server;
+ packet->sock = sock;
+ if (srvr) {
+ packet->cipher = srvr->receive_key;
+ packet->hmac = srvr->hmac;
+ }
+ silc_buffer_clear(sock->inbuf);
+
+ /* The packet is ready to be parsed now. However, this is a client
+ connection so we will parse the packet with timeout. */
+ silc_task_register(server->timeout_queue, fd,
+ silc_server_packet_parse,
+ (void *)packet, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+ }
+
+ /* Decrypt a packet coming from client. */
+ if (sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
+ SilcIDListUnknown *conn_data = (SilcIDListUnknown *)sock->user_data;
+ SilcServerInternalPacket *packet;
+
+ SILC_LOG_HEXDUMP(("Incoming packet, len %d", sock->inbuf->len),
+ sock->inbuf->data, sock->inbuf->len);
+
+ SILC_LOG_DEBUG(("Packet from unknown connection, length %d",
+ paddedlen));
+
+ packet = silc_calloc(1, sizeof(*packet));
+ packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+ packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+ packet->server = server;
+ packet->sock = sock;
+ if (conn_data) {
+ packet->cipher = conn_data->receive_key;
+ packet->hmac = conn_data->hmac;
+ }
+
+ silc_buffer_clear(sock->inbuf);
+
+ /* The packet is ready to be parsed now. However, this is unknown
+ connection so we will parse the packet with timeout. */
+ silc_task_register(server->timeout_queue, fd,
+ silc_server_packet_parse,
+ (void *)packet, 0, 100000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+ }
+
+ SILC_LOG_ERROR(("Weird, nothing happened - ignoring"));
+}
+
+/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
+ after packet has been totally decrypted and parsed. */
+
+static int silc_server_packet_check_mac(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcHmac hmac = NULL;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned int mac_len = 0;
+
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ if (sock->user_data) {
+ hmac = ((SilcClientList *)sock->user_data)->hmac;
+ hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
+ }
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ if (sock->user_data) {
+ hmac = ((SilcServerList *)sock->user_data)->hmac;
+ hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
+ }
+ break;
+ default:
+ if (sock->user_data) {
+ hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+ hmac_key = ((SilcIDListUnknown *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcIDListUnknown *)sock->user_data)->hmac_key_len;
+ }
+ }
+
+ /* Check MAC */
+ if (hmac) {
+ int headlen = buffer->data - buffer->head;
+ unsigned char *packet_mac, mac[32];
+
+ SILC_LOG_DEBUG(("Verifying MAC"));
+
+ mac_len = hmac->hash->hash->hash_len;
+
+ silc_buffer_push(buffer, headlen);
+
+ /* Take mac from packet */
+ packet_mac = buffer->tail;
+
+ /* Make MAC and compare */
+ memset(mac, 0, sizeof(mac));
+ silc_hmac_make_with_key(hmac,
+ buffer->data, buffer->len,
+ hmac_key, hmac_key_len, mac);
+#if 0
+ SILC_LOG_HEXDUMP(("PMAC"), packet_mac, mac_len);
+ SILC_LOG_HEXDUMP(("CMAC"), mac, mac_len);
+#endif
+ if (memcmp(mac, packet_mac, mac_len)) {
+ SILC_LOG_DEBUG(("MAC failed"));
+ return FALSE;
+ }
+
+ SILC_LOG_DEBUG(("MAC is Ok"));
+ memset(mac, 0, sizeof(mac));
+
+ silc_buffer_pull(buffer, headlen);
+ }
+
+ return TRUE;
+}
+
+/* Decrypts rest of the packet (after decrypting just the SILC header).
+ After calling this function the packet is ready to be parsed by calling
+ silc_packet_parse. */
+
+static int silc_server_packet_decrypt_rest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcCipher session_key = NULL;
+ SilcHmac hmac = NULL;
+ unsigned int mac_len = 0;
+
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ if (sock->user_data) {
+ session_key = ((SilcClientList *)sock->user_data)->receive_key;
+ hmac = ((SilcClientList *)sock->user_data)->hmac;
+ }
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ if (sock->user_data) {
+ session_key = ((SilcServerList *)sock->user_data)->receive_key;
+ hmac = ((SilcServerList *)sock->user_data)->hmac;
+ }
+ break;
+ default:
+ if (sock->user_data) {
+ session_key = ((SilcIDListUnknown *)sock->user_data)->receive_key;
+ hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+ }
+ }
+
+ /* Decrypt */
+ if (session_key) {
+
+ /* Pull MAC from packet before decryption */
+ if (hmac) {
+ mac_len = hmac->hash->hash->hash_len;
+ if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+ silc_buffer_push_tail(buffer, mac_len);
+ } else {
+ SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+ return FALSE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("Decrypting rest of the packet"));
+
+ /* Decrypt rest of the packet */
+ silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+ silc_packet_decrypt(session_key, buffer, buffer->len);
+ silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+
+ SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
+ buffer->data, buffer->len);
+ }
+
+ return TRUE;
+}
+
+/* Decrypts rest of the SILC Packet header that has been decrypted partly
+ already. This decrypts the padding of the packet also. After calling
+ this function the packet is ready to be parsed by calling function
+ silc_packet_parse. */
+
+static int silc_server_packet_decrypt_rest_special(SilcServer server,
+ SilcSocketConnection sock,
+ SilcBuffer buffer)
+{
+ SilcCipher session_key = NULL;
+ SilcHmac hmac = NULL;
+ unsigned int mac_len = 0;
+
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ if (sock->user_data) {
+ session_key = ((SilcClientList *)sock->user_data)->receive_key;
+ hmac = ((SilcClientList *)sock->user_data)->hmac;
+ }
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ if (sock->user_data) {
+ session_key = ((SilcServerList *)sock->user_data)->receive_key;
+ hmac = ((SilcServerList *)sock->user_data)->hmac;
+ }
+ break;
+ default:
+ if (sock->user_data) {
+ session_key = ((SilcIDListUnknown *)sock->user_data)->receive_key;
+ hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+ }
+ }
+
+ /* Decrypt rest of the header plus padding */
+ if (session_key) {
+ unsigned short truelen, len1, len2, padlen;
+
+ /* Pull MAC from packet before decryption */
+ if (hmac) {
+ mac_len = hmac->hash->hash->hash_len;
+ if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+ silc_buffer_push_tail(buffer, mac_len);
+ } else {
+ SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+ return FALSE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("Decrypting rest of the header"));
+
+ SILC_GET16_MSB(len1, &buffer->data[4]);
+ SILC_GET16_MSB(len2, &buffer->data[6]);
+
+ truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
+ padlen = SILC_PACKET_PADLEN(truelen);
+ len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
+
+ silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+ silc_packet_decrypt(session_key, buffer, len1);
+ silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+ }
+
+ return TRUE;
+}
+
+/* Parses whole packet, received earlier. This packet is usually received
+ from client. */
+
+SILC_TASK_CALLBACK(silc_server_packet_parse)
+{
+ SilcServerInternalPacket *packet = (SilcServerInternalPacket *)context;
+ SilcServer server = packet->server;
+ SilcSocketConnection sock = packet->sock;
+ SilcBuffer buffer = packet->packetdata->buffer;
+ int ret;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decrypt start of the packet header */
+ if (packet->cipher)
+ silc_packet_decrypt(packet->cipher, buffer, SILC_PACKET_MIN_HEADER_LEN);
+
+ /* If the packet type is not any special type lets decrypt rest
+ of the packet here. */
+ if (buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE &&
+ buffer->data[3] != SILC_PACKET_PRIVATE_MESSAGE) {
+ normal:
+ /* Normal packet, decrypt rest of the packet */
+ if (!silc_server_packet_decrypt_rest(server, sock, buffer))
+ goto out;
+
+ /* Parse the packet. Packet type is returned. */
+ ret = silc_packet_parse(packet->packetdata);
+ if (ret == SILC_PACKET_NONE)
+ goto out;
+
+ /* Check MAC */
+ if (!silc_server_packet_check_mac(server, sock, buffer))
+ goto out;
+ } else {
+ /* If private message key is not set for private message it is
+ handled as normal packet. Go back up. */
+ if (buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+ !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+ goto normal;
+
+ /* Packet requires special handling, decrypt rest of the header.
+ This only decrypts. This does not do any MAC checking, it must
+ be done individually later when doing the special processing. */
+ silc_server_packet_decrypt_rest_special(server, sock, buffer);
+
+ /* Parse the packet header in special way as this is "special"
+ packet type. */
+ ret = silc_packet_parse_special(packet->packetdata);
+ if (ret == SILC_PACKET_NONE)
+ goto out;
+ }
+
+ /* Parse the incoming packet type */
+ silc_server_packet_parse_type(server, sock, packet->packetdata);
+
+ out:
+ silc_buffer_clear(sock->inbuf);
+ // silc_buffer_free(packetdata->packetdata->buffer);
+ silc_free(packet->packetdata);
+ silc_free(packet);
+}
+
+/* Parses the packet type and calls what ever routines the packet type
+ requires. This is done for all incoming packets. */
+
+void silc_server_packet_parse_type(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcPacketType type = packet->type;
+
+ SILC_LOG_DEBUG(("Parsing packet type %d", type));
+
+ /* Parse the packet type */
+ switch(type) {
+ case SILC_PACKET_DISCONNECT:
+ SILC_LOG_DEBUG(("Disconnect packet"));
+ break;
+ case SILC_PACKET_SUCCESS:
+ /*
+ * Success received for something. For now we can have only
+ * one protocol for connection executing at once hence this
+ * success message is for whatever protocol is executing currently.
+ */
+ SILC_LOG_DEBUG(("Success packet"));
+ if (sock->protocol) {
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ }
+ break;
+ case SILC_PACKET_FAILURE:
+ SILC_LOG_DEBUG(("Failure packet"));
+ break;
+ case SILC_PACKET_REJECT:
+ SILC_LOG_DEBUG(("Reject packet"));
+ return;
+ break;
+
+ /*
+ * Channel packets
+ */
+ case SILC_PACKET_CHANNEL_MESSAGE:
+ /*
+ * Received channel message. Channel messages are special packets
+ * (although probably most common ones) hence they are handled
+ * specially.
+ */
+ SILC_LOG_DEBUG(("Channel Message packet"));
+ silc_server_channel_message(server, sock, packet);
+ break;
+
+ case SILC_PACKET_CHANNEL_KEY:
+ /*
+ * Received key for channel. As channels are created by the router
+ * the keys are as well. We will distribute the key to all of our
+ * locally connected clients on the particular channel. Router
+ * never receives this channel and thus is ignored.
+ */
+ SILC_LOG_DEBUG(("Channel Key packet"));
+ silc_server_channel_key(server, sock, packet);
+ break;
+
+ /*
+ * Command packets
+ */
+ case SILC_PACKET_COMMAND:
+ {
+ /*
+ * Recived command. Allocate command context and execute the command.
+ */
+ SilcServerCommandContext ctx;
+
+ SILC_LOG_DEBUG(("Command packet"));
+
+ /* Router cannot send command packet */
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER)
+ break;
+
+ /* Allocate command context. This must be free'd by the
+ command routine receiving it. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->server = server;
+ ctx->sock = sock;
+ ctx->packet = packet; /* Save original packet */
+
+ /* Parse the command payload in the packet */
+ ctx->payload = silc_command_parse_payload(buffer);
+ if (!ctx->payload) {
+ SILC_LOG_ERROR(("Bad command payload, packet dropped"));
+ silc_free(ctx);
+ return;
+ }
+
+ /* Execute command. If this fails the packet is dropped. */
+ SILC_SERVER_COMMAND_EXEC(ctx);
+ silc_buffer_free(buffer);
+ }
+ break;
+
+ case SILC_PACKET_COMMAND_REPLY:
+ /*
+ * Received command reply packet. Servers never send commands thus
+ * they don't receive command reply packets either, except in cases
+ * where server has forwarded command packet coming from client.
+ * This must be the case here or we will ignore the packet.
+ */
+ SILC_LOG_DEBUG(("Command Reply packet"));
+ silc_server_packet_relay_command_reply(server, sock, packet);
+ break;
+
+ /*
+ * Private Message packets
+ */
+ case SILC_PACKET_PRIVATE_MESSAGE:
+ /*
+ * Received private message packet. The packet is coming from either
+ * client or server.
+ */
+ SILC_LOG_DEBUG(("Private Message packet"));
+ silc_server_private_message(server, sock, packet);
+ break;
+
+ case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+ break;
+
+ /*
+ * Key Exchange protocol packets
+ */
+ case SILC_PACKET_KEY_EXCHANGE:
+ SILC_LOG_DEBUG(("KE packet"));
+ if (sock->protocol && sock->protocol->protocol->type
+ == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+
+ SilcServerKEInternalContext *proto_ctx =
+ (SilcServerKEInternalContext *)sock->protocol->context;
+
+ proto_ctx->packet = buffer;
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 100000);
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
+ "protocol active, packet dropped."));
+
+ /* XXX Trigger KE protocol?? Rekey actually, maybe. */
+ }
+ break;
+
+ case SILC_PACKET_KEY_EXCHANGE_1:
+ SILC_LOG_DEBUG(("KE 1 packet"));
+ if (sock->protocol && sock->protocol->protocol->type
+ == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+
+ SilcServerKEInternalContext *proto_ctx =
+ (SilcServerKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_buffer_free(proto_ctx->packet);
+
+ proto_ctx->packet = buffer;
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
+ "protocol active, packet dropped."));
+ }
+ break;
+
+ case SILC_PACKET_KEY_EXCHANGE_2:
+ SILC_LOG_DEBUG(("KE 2 packet"));
+ if (sock->protocol && sock->protocol->protocol->type
+ == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+
+ SilcServerKEInternalContext *proto_ctx =
+ (SilcServerKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_buffer_free(proto_ctx->packet);
+
+ proto_ctx->packet = buffer;
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
+ "protocol active, packet dropped."));
+ }
+ break;
+
+ case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+ /* If we receive this packet we will send to the other end information
+ about our mandatory authentication method for the connection.
+ This packet maybe received at any time. */
+
+ /*
+ * Connection Authentication protocol packets
+ */
+ case SILC_PACKET_CONNECTION_AUTH:
+ /* Start of the authentication protocol. We receive here the
+ authentication data and will verify it. */
+ SILC_LOG_DEBUG(("Connection auth packet"));
+ if (sock->protocol && sock->protocol->protocol->type
+ == SILC_PROTOCOL_SERVER_CONNECTION_AUTH) {
+
+ SilcServerConnAuthInternalContext *proto_ctx =
+ (SilcServerConnAuthInternalContext *)sock->protocol->context;
+
+ proto_ctx->packet = buffer;
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
+ "protocol active, packet dropped."));
+ }
+ break;
+
+ case SILC_PACKET_NEW_ID:
+ /*
+ * Received New ID packet. This includes some new ID that has been
+ * created. It may be for client, server or channel. This is the way
+ * to distribute information about new registered entities in the
+ * SILC network.
+ */
+ SILC_LOG_DEBUG(("New ID packet"));
+ silc_server_new_id(server, sock, packet);
+ break;
+
+ case SILC_PACKET_NEW_CLIENT:
+ /*
+ * Received new client packet. This includes client information that
+ * we will use to create initial client ID. After creating new
+ * ID we will send it to the client.
+ */
+ SILC_LOG_DEBUG(("New Client packet"));
+ silc_server_new_client(server, sock, packet);
+ break;
+
+ case SILC_PACKET_NEW_SERVER:
+ /*
+ * Received new server packet. This includes Server ID and some other
+ * information that we may save. This is after server as connected to us.
+ */
+ SILC_LOG_DEBUG(("New Server packet"));
+ silc_server_new_server(server, sock, packet);
+ break;
+
+ default:
+ SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
+ break;
+ }
+
+}
+
+/* Internal routine that sends packet or marks packet to be sent. This
+ is used directly only in special cases. Normal cases should use
+ silc_server_packet_send. Returns < 0 error. */
+
+static int silc_server_packet_send_real(SilcServer server,
+ SilcSocketConnection sock,
+ int force_send)
+{
+ /* Send now if forced to do so */
+ if (force_send == TRUE) {
+ int ret;
+ SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
+ ret = silc_packet_write(sock->sock, sock->outbuf);
+
+ silc_buffer_clear(sock->outbuf);
+
+ if (ret == -1)
+ SILC_LOG_ERROR(("Could not write, packet dropped"));
+ if (ret != -2) {
+ silc_buffer_clear(sock->outbuf);
+ return ret;
+ }
+
+ SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
+ }
+
+ SILC_LOG_DEBUG(("Packet in queue"));
+
+ /* Mark that there is some outgoing data available for this connection.
+ This call sets the connection both for input and output (the input
+ is set always and this call keeps the input setting, actually).
+ Actual data sending is performed by silc_server_packet_process. */
+ SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+
+ /* Mark to socket that data is pending in outgoing buffer. This flag
+ is needed if new data is added to the buffer before the earlier
+ put data is sent to the network. */
+ SILC_SET_OUTBUF_PENDING(sock);
+
+ return 0;
+}
+
+/* Prepare outgoing data buffer for packet sending. This is internal
+ routine and must always be called before sending any packets out. */
+
+static void silc_server_packet_send_prepare(SilcServer server,
+ SilcSocketConnection sock,
+ unsigned int header_len,
+ unsigned int padlen,
+ unsigned int data_len)
+{
+ int totlen, oldlen;
+
+ totlen = header_len + padlen + data_len;
+
+ /* Prepare the outgoing buffer for packet sending. */
+ if (!sock->outbuf) {
+ /* Allocate new buffer. This is done only once per connection. */
+ SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
+
+ sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+ silc_buffer_pull_tail(sock->outbuf, totlen);
+ silc_buffer_pull(sock->outbuf, header_len + padlen);
+ } else {
+ if (SILC_IS_OUTBUF_PENDING(sock)) {
+ /* There is some pending data in the buffer. */
+
+ if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
+ SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+ /* XXX: not done yet */
+ }
+ oldlen = sock->outbuf->len;
+ silc_buffer_pull_tail(sock->outbuf, totlen);
+ silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
+ } else {
+ /* Buffer is free for use */
+ silc_buffer_clear(sock->outbuf);
+ silc_buffer_pull_tail(sock->outbuf, totlen);
+ silc_buffer_pull(sock->outbuf, header_len + padlen);
+ }
+ }
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+ send the packet but creates the packet and fills the outgoing data
+ buffer and marks the packet ready to be sent to network. However, If
+ argument force_send is TRUE the packet is sent immediately and not put
+ to queue. Normal case is that the packet is not sent immediately. */
+
+void silc_server_packet_send(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ void *dst_id = NULL;
+ SilcIdType dst_id_type = SILC_ID_NONE;
+
+ /* Get data used in the packet sending, keys and stuff */
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ if (((SilcClientList *)sock->user_data)->id) {
+ dst_id = ((SilcClientList *)sock->user_data)->id;
+ dst_id_type = SILC_ID_CLIENT;
+ }
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ if (((SilcServerList *)sock->user_data)->id) {
+ dst_id = ((SilcServerList *)sock->user_data)->id;
+ dst_id_type = SILC_ID_SERVER;
+ }
+ break;
+ default:
+ break;
+ }
+
+ silc_server_packet_send_dest(server, sock, type, flags, dst_id,
+ dst_id_type, data, data_len, force_send);
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+ send the packet but creates the packet and fills the outgoing data
+ buffer and marks the packet ready to be sent to network. However, If
+ argument force_send is TRUE the packet is sent immediately and not put
+ to queue. Normal case is that the packet is not sent immediately.
+ Destination information is sent as argument for this function. */
+
+void silc_server_packet_send_dest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ SilcPacketContext packetdata;
+ SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+ unsigned char *dst_id_data = NULL;
+ unsigned int dst_id_len = 0;
+
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+ /* Get data used in the packet sending, keys and stuff */
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ if (sock->user_data) {
+ cipher = ((SilcClientList *)sock->user_data)->send_key;
+ hmac = ((SilcClientList *)sock->user_data)->hmac;
+ if (hmac) {
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
+ }
+ }
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ if (sock->user_data) {
+ cipher = ((SilcServerList *)sock->user_data)->send_key;
+ hmac = ((SilcServerList *)sock->user_data)->hmac;
+ if (hmac) {
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
+ }
+ }
+ break;
+ default:
+ if (sock->user_data) {
+ /* We don't know what type of connection this is thus it must
+ be in authentication phase. */
+ cipher = ((SilcIDListUnknown *)sock->user_data)->send_key;
+ hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+ if (hmac) {
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = ((SilcIDListUnknown *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcIDListUnknown *)sock->user_data)->hmac_key_len;
+ }
+ }
+ break;
+ }
+
+ if (dst_id) {
+ dst_id_data = silc_id_id2str(dst_id, dst_id_type);
+ dst_id_len = silc_id_get_len(dst_id_type);
+ }
+
+ /* Set the packet context pointers */
+ packetdata.type = type;
+ packetdata.flags = flags;
+ packetdata.src_id = silc_id_id2str(server->id, server->id_type);
+ packetdata.src_id_len = SILC_ID_SERVER_LEN;
+ packetdata.src_id_type = server->id_type;
+ packetdata.dst_id = dst_id_data;
+ packetdata.dst_id_len = dst_id_len;
+ packetdata.dst_id_type = dst_id_type;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+ packetdata.rng = server->rng;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+
+ SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the data to the buffer */
+ if (data && data_len)
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet */
+ if (hmac) {
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+ }
+
+ /* Encrypt the packet */
+ if (cipher)
+ silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
+
+ /* Pull MAC into the visible data area */
+ if (hmac)
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+
+ if (packetdata.src_id)
+ silc_free(packetdata.src_id);
+ if (packetdata.dst_id)
+ silc_free(packetdata.dst_id);
+}
+
+/* Forwards packet. Packets sent with this function will be marked as
+ forwarded (in the SILC header flags) so that the receiver knows that
+ we have forwarded the packet to it. Forwarded packets are handled
+ specially by the receiver as they are not destined to the receiver
+ originally. However, the receiver knows this because the forwarded
+ flag has been set (and the flag is authenticated). */
+
+void silc_server_packet_forward(SilcServer server,
+ SilcSocketConnection sock,
+ unsigned char *data, unsigned int data_len,
+ int force_send)
+{
+ SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+
+ SILC_LOG_DEBUG(("Forwarding packet"));
+
+ /* Get data used in the packet sending, keys and stuff */
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ if (sock->user_data) {
+ cipher = ((SilcClientList *)sock->user_data)->send_key;
+ hmac = ((SilcClientList *)sock->user_data)->hmac;
+ if (hmac) {
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
+ }
+ }
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ if (sock->user_data) {
+ cipher = ((SilcServerList *)sock->user_data)->send_key;
+ hmac = ((SilcServerList *)sock->user_data)->hmac;
+ if (hmac) {
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
+ hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
+ }
+ }
+ break;
+ default:
+ /* We won't forward to unknown destination - keys must exist with
+ the destination before forwarding. */
+ return;
+ }
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock, 0, 0, data_len);
+
+ /* Mungle the packet flags and add the FORWARDED flag */
+ if (data)
+ data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
+
+ /* Put the data to the buffer */
+ if (data && data_len)
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Compute MAC of the packet */
+ if (hmac) {
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+ }
+
+ /* Encrypt the packet */
+ if (cipher)
+ silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
+
+ /* Pull MAC into the visible data area */
+ if (hmac)
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+}
+
+/* This routine is used by the server to send packets to channel. The
+ packet sent with this function is distributed to all clients on
+ the channel. Usually this is used to send notify messages to the
+ channel, things like notify about new user joining to the channel. */
+
+void silc_server_packet_send_to_channel(SilcServer server,
+ SilcChannelList *channel,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ int i;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientList *client = NULL;
+ SilcServerList **routed = NULL;
+ unsigned int routed_count = 0;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+ SilcCipher cipher;
+ SilcHmac hmac;
+ SilcBuffer payload;
+
+ SILC_LOG_DEBUG(("Sending packet to channel"));
+
+ /* Generate IV */
+ for (i = 0; i < 16; i++)
+ channel->iv[i] = silc_rng_get_byte(server->rng);
+
+ /* Encode the channel payload */
+ payload = silc_channel_encode_payload(0, "", data_len, data,
+ 16, channel->iv, server->rng);
+ if (!payload)
+ return;
+
+ /* Encrypt payload of the packet. This is encrypted with the
+ channel key. */
+ channel->channel_key->cipher->encrypt(channel->channel_key->context,
+ payload->data, payload->data,
+ payload->len - 16, /* -IV_LEN */
+ channel->iv);
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+ packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packetdata.src_id_len = SILC_ID_SERVER_LEN;
+ packetdata.src_id_type = SILC_ID_SERVER;
+ packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+ packetdata.dst_id_type = SILC_ID_CHANNEL;
+ packetdata.rng = server->rng;
+ packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len));
+
+ /* If there are global users in the channel we will send the message
+ first to our router for further routing. */
+ if (server->server_type == SILC_SERVER && !server->standalone &&
+ channel->global_users) {
+ SilcServerList *router;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ router = server->id_entry->router;
+ sock = (SilcSocketConnection)router->connection;
+ cipher = router->send_key;
+ hmac = router->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = router->hmac_key;
+ hmac_key_len = router->hmac_key_len;
+
+ SILC_LOG_DEBUG(("Sending packet to router for routing"));
+
+ packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ payload->len);
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the original packet into the buffer. */
+ silc_buffer_put(sock->outbuf, payload->data, payload->len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet. MAC is computed from the header,
+ padding and the relayed packet. */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with the client. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+ }
+
+ /* Send the message to clients on the channel's client list. */
+ for (i = 0; i < channel->user_list_count; i++) {
+ client = channel->user_list[i].client;
+
+ /* If client has router set it is not locally connected client and
+ we will route the message to the router set in the client. */
+ if (client && client->router && server->server_type == SILC_ROUTER) {
+ int k;
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->router->connection;
+ cipher = client->router->send_key;
+ hmac = client->router->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = client->router->hmac_key;
+ hmac_key_len = client->router->hmac_key_len;
+
+ packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ payload->len);
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the encrypted payload data into the buffer. */
+ silc_buffer_put(sock->outbuf, payload->data, payload->len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet. MAC is computed from the header,
+ padding and the relayed packet. */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with the client. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ k = routed_count;
+ routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+ routed[k] = client->router;
+ routed_count++;
+
+ continue;
+ }
+
+ /* Send to locally connected client */
+ if (client) {
+
+ /* XXX Check client's mode on the channel. */
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->connection;
+ cipher = client->send_key;
+ hmac = client->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = client->hmac_key;
+ hmac_key_len = client->hmac_key_len;
+
+ packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ payload->len);
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the encrypted payload data into the buffer. */
+ silc_buffer_put(sock->outbuf, payload->data, payload->len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet. MAC is computed from the header,
+ padding and the relayed packet. */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with the client. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+ }
+ }
+
+ if (routed_count)
+ silc_free(routed);
+ silc_free(packetdata.src_id);
+ silc_free(packetdata.dst_id);
+ silc_buffer_free(payload);
+}
+
+/* This routine is explicitly used to relay messages to some channel.
+ Packets sent with this function we have received earlier and are
+ totally encrypted. This just sends the packet to all clients on
+ the channel. If the sender of the packet is someone on the channel
+ the message will not be sent to that client. The SILC Packet header
+ is encrypted with the session key shared between us and the client.
+ MAC is also computed before encrypting the header. Rest of the
+ packet will be untouched. */
+
+void silc_server_packet_relay_to_channel(SilcServer server,
+ SilcSocketConnection sender_sock,
+ SilcChannelList *channel,
+ void *sender,
+ SilcIdType sender_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ int i, found = FALSE;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientList *client = NULL;
+ SilcServerList **routed = NULL;
+ unsigned int routed_count = 0;
+ unsigned char *hmac_key = NULL;
+ unsigned int hmac_key_len = 0;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+ SilcCipher cipher;
+ SilcHmac hmac;
+
+ SILC_LOG_DEBUG(("Relaying packet to channel"));
+
+ SILC_LOG_HEXDUMP(("XXX %d", data_len), data, data_len);
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+ packetdata.src_id = silc_id_id2str(sender, sender_type);
+ packetdata.src_id_len = silc_id_get_len(sender_type);
+ packetdata.src_id_type = sender_type;
+ packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+ packetdata.dst_id_type = SILC_ID_CHANNEL;
+ packetdata.rng = server->rng;
+ packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len));
+
+ /* If there are global users in the channel we will send the message
+ first to our router for further routing. */
+ if (server->server_type == SILC_SERVER && !server->standalone &&
+ channel->global_users) {
+ SilcServerList *router;
+
+ router = server->id_entry->router;
+
+ /* Check that the sender is not our router. */
+ if (sender_sock != (SilcSocketConnection)router->connection) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)router->connection;
+ cipher = router->send_key;
+ hmac = router->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = router->hmac_key;
+ hmac_key_len = router->hmac_key_len;
+
+ SILC_LOG_DEBUG(("Sending packet to router for routing"));
+
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the original packet into the buffer. */
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet. MAC is computed from the header,
+ padding and the relayed packet. */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with the client. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+ }
+ }
+
+ /* Send the message to clients on the channel's client list. */
+ for (i = 0; i < channel->user_list_count; i++) {
+ client = channel->user_list[i].client;
+
+ if (client) {
+
+ /* If sender is one on the channel do not send it the packet. */
+ if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
+ found = TRUE;
+ continue;
+ }
+
+ /* If the client has set router it means that it is not locally
+ connected client and we won't send message to those in this
+ function (they will be routed separately by the caller). */
+ if (server->server_type == SILC_ROUTER && client->router) {
+ int k;
+
+ /* Sender maybe server as well so we want to make sure that
+ we won't send the message to the server it came from. */
+ if (!found && !SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
+ found = TRUE;
+ continue;
+ }
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->router->connection;
+ cipher = client->router->send_key;
+ hmac = client->router->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = client->router->hmac_key;
+ hmac_key_len = client->router->hmac_key_len;
+
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the original packet into the buffer. */
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet. MAC is computed from the header,
+ padding and the relayed packet. */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with the client. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ k = routed_count;
+ routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+ routed[k] = client->router;
+ routed_count++;
+
+ continue;
+ }
+
+ /* XXX Check client's mode on the channel. */
+
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->connection;
+ cipher = client->send_key;
+ hmac = client->hmac;
+ mac_len = hmac->hash->hash->hash_len;
+ hmac_key = client->hmac_key;
+ hmac_key_len = client->hmac_key_len;
+
+ SILC_LOG_DEBUG(("Sending packet to client %s",
+ sock->hostname ? sock->hostname : sock->ip));
+
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_server_packet_send_prepare(server, sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the original packet into the buffer. */
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ /* Compute MAC of the packet. MAC is computed from the header,
+ padding and the relayed packet. */
+ silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+ hmac_key, hmac_key_len, mac);
+ silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with the client. */
+ silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ /* Pull MAC into the visible data area */
+ silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+ SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+ }
+ }
+
+ silc_free(packetdata.src_id);
+ silc_free(packetdata.dst_id);
+}
+
+/* Relays received command reply packet to the correct destination. The
+ destination must be one of our locally connected client or the packet
+ will be ignored. This is called when server has forwarded one of
+ client's command request to router and router has now replied to the
+ command. */
+
+void silc_server_packet_relay_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcClientList *client;
+ SilcClientID *id;
+ SilcSocketConnection dst_sock;
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Source must be server or router */
+ /* XXX: actually it must be only router */
+ if (packet->src_id_type != SILC_ID_SERVER &&
+ (sock->type != SILC_SOCKET_TYPE_SERVER ||
+ sock->type != SILC_SOCKET_TYPE_ROUTER))
+ goto out;
+
+ /* Destination must be client */
+ if (packet->dst_id_type != SILC_ID_CLIENT)
+ goto out;
+
+ /* Execute command reply locally for the command */
+ silc_server_command_reply_process(server, sock, buffer);
+
+ id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+
+ /* Destination must be one of ours */
+ client = silc_idlist_find_client_by_id(server->local_list->clients, id);
+ if (!client) {
+ silc_free(id);
+ goto out;
+ }
+
+ /* Relay the packet to the client */
+ if (client->hmac)
+ mac_len = client->hmac->hash->hash->hash_len;
+
+ dst_sock = (SilcSocketConnection)client->connection;
+
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ /* Compute new HMAC */
+ if (client->hmac) {
+ memset(mac, 0, sizeof(mac));
+ silc_hmac_make_with_key(client->hmac,
+ dst_sock->outbuf->data,
+ dst_sock->outbuf->len,
+ client->hmac_key,
+ client->hmac_key_len,
+ mac);
+ silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+ }
+
+ /* Encrypt */
+ if (client && client->send_key)
+ silc_packet_encrypt(client->send_key, dst_sock->outbuf, buffer->len);
+
+ if (client->hmac)
+ silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+
+ silc_free(id);
+
+ out:
+ silc_buffer_free(buffer);
+}
+
+/* Closes connection to socket connection */
+
+void silc_server_close_connection(SilcServer server,
+ SilcSocketConnection sock)
+{
+
+ SILC_LOG_DEBUG(("Closing connection %d", sock->sock));
+
+ /* We won't listen for this connection anymore */
+ silc_schedule_unset_listen_fd(sock->sock);
+
+ /* Unregister all tasks */
+ silc_task_unregister_by_fd(server->io_queue, sock->sock);
+ silc_task_unregister_by_fd(server->timeout_queue, sock->sock);
+
+ /* Close the actual connection */
+ silc_net_close_connection(sock->sock);
+ server->sockets[sock->sock] = NULL;
+ silc_socket_free(sock);
+}
+
+/* Sends disconnect message to remote connection and disconnects the
+ connection. */
+
+void silc_server_disconnect_remote(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...)
+{
+ va_list ap;
+ unsigned char buf[4096];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ SILC_LOG_DEBUG(("Disconnecting remote host"));
+
+ /* Notify remote end that the conversation is over. The notify message
+ is tried to be sent immediately. */
+ silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,
+ buf, strlen(buf), TRUE);
+
+ /* Mark the connection to be disconnected */
+ SILC_SET_DISCONNECTED(sock);
+ silc_server_close_connection(server, sock);
+}
+
+/* Free's user_data pointer from socket connection object. As this
+ pointer maybe anything we wil switch here to find the corrent
+ data type and free it the way it needs to be free'd. */
+
+void silc_server_free_sock_user_data(SilcServer server,
+ SilcSocketConnection sock)
+{
+ SILC_LOG_DEBUG(("Start"));
+
+#define LCC(x) server->local_list->client_cache[(x) - 32]
+#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+
+ switch(sock->type) {
+ case SILC_SOCKET_TYPE_CLIENT:
+ {
+ SilcClientList *user_data = (SilcClientList *)sock->user_data;
+
+ /* Remove client from all channels */
+ silc_server_remove_from_channels(server, sock, user_data);
+
+ /* Clear ID cache */
+ if (user_data->nickname && user_data->id)
+ silc_idcache_del_by_id(LCC(user_data->nickname[0]),
+ LCCC(user_data->nickname[0]),
+ SILC_ID_CLIENT, user_data->id);
+
+ /* Free the client entry and everything in it */
+ /* XXX must take some info to history before freeing */
+ silc_idlist_del_client(&server->local_list->clients, user_data);
+ break;
+ }
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ {
+
+ break;
+ }
+ break;
+ default:
+ {
+ SilcIDListUnknown *user_data = (SilcIDListUnknown *)sock->user_data;
+
+ if (user_data->send_key)
+ silc_cipher_free(user_data->send_key);
+ if (user_data->receive_key)
+ silc_cipher_free(user_data->receive_key);
+ if (user_data->pkcs)
+ silc_pkcs_free(user_data->pkcs);
+ if (user_data->hmac) {
+ silc_hmac_free(user_data->hmac);
+ memset(user_data->hmac_key, 0, user_data->hmac_key_len);
+ silc_free(user_data->hmac_key);
+ }
+ silc_free(user_data);
+ break;
+ }
+ }
+
+ sock->user_data = NULL;
+#undef LCC
+#undef LCCC
+}
+
+/* Removes client from all channels it has joined. This is used when
+ client connection is disconnected. If the client on a channel
+ is last, the channel is removed as well. */
+
+void silc_server_remove_from_channels(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientList *client)
+{
+ int i, k;
+ SilcChannelList *channel;
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+ /* Remove the client from all channels. The client is removed from
+ the channels' user list. */
+ for (i = 0; i < client->channel_count; i++) {
+ channel = client->channel[i];
+ if (!channel)
+ continue;
+
+ /* Remove from channel */
+ for (k = 0; k < channel->user_list_count; k++) {
+ if (channel->user_list[k].client == client) {
+
+ /* If this client is last one on the channel the channel
+ is removed all together. */
+ if (channel->user_list_count == 1) {
+ silc_idcache_del_by_id(LCC(channel->channel_name[0]),
+ LCCC(channel->channel_name[0]),
+ SILC_ID_CHANNEL, channel->id);
+ silc_idlist_del_channel(&server->local_list->channels, channel);
+ break;
+ }
+
+ channel->user_list[k].client = NULL;
+ channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+
+ /* XXX */
+ /* Send notify to channel about client leaving SILC and thus
+ the entire channel. */
+ silc_server_send_notify_to_channel(server, channel,
+ "%s has left channel %s",
+ client->nickname,
+ channel->channel_name);
+ }
+ }
+ }
+
+ if (client->channel_count)
+ silc_free(client->channel);
+ client->channel = NULL;
+#undef LCC
+#undef LCCC
+}
+
+/* Timeout callback. This is called if connection is idle or for some
+ other reason is not responding within some period of time. This
+ disconnects the remote end. */
+
+SILC_TASK_CALLBACK(silc_server_timeout_remote)
+{
+ SilcServer server = (SilcServer)context;
+ SilcSocketConnection sock = server->sockets[fd];
+
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Connection timeout");
+}
+
+/* Internal routine used to send (relay, route) private messages to some
+ destination. This is used to by normal server to send the message to
+ its primary route and router uses this to send it to any route it
+ wants. If the private message key does not exist then the message
+ is re-encrypted, otherwise we just pass it along. */
+static void
+silc_server_private_message_send_internal(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcServerList *router,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+
+ /* Send and re-encrypt if private messge key does not exist */
+ if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+
+ if (router->hmac)
+ mac_len = router->hmac->hash->hash->hash_len;
+
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ /* Compute new HMAC */
+ if (router->hmac) {
+ mac_len = router->hmac->hash->hash->hash_len;
+ memset(mac, 0, sizeof(mac));
+ silc_hmac_make_with_key(router->hmac,
+ dst_sock->outbuf->data,
+ dst_sock->outbuf->len,
+ router->hmac_key,
+ router->hmac_key_len,
+ mac);
+ silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+ }
+
+ silc_packet_encrypt(router->send_key, dst_sock->outbuf, buffer->len);
+
+ if (router->hmac)
+ silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+
+ } else {
+ /* Key exist so just send it */
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+ }
+}
+
+/* Internal routine to send the received private message packet to
+ our locally connected client. */
+static void
+silc_server_private_message_send_local(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcClientList *client,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+
+ /* Re-encrypt packet if needed */
+ if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+ unsigned char mac[32];
+ unsigned int mac_len = 0;
+
+ if (client->hmac)
+ mac_len = client->hmac->hash->hash->hash_len;
+
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ /* Compute new HMAC */
+ if (client->hmac) {
+ memset(mac, 0, sizeof(mac));
+ silc_hmac_make_with_key(client->hmac,
+ dst_sock->outbuf->data,
+ dst_sock->outbuf->len,
+ client->hmac_key,
+ client->hmac_key_len,
+ mac);
+ silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
+ memset(mac, 0, sizeof(mac));
+ }
+
+ /* Encrypt */
+ if (client && client->send_key)
+ silc_packet_encrypt(client->send_key, dst_sock->outbuf,
+ buffer->len);
+
+ if (client->hmac)
+ silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+ } else {
+ /* Key exist so just send it */
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+ }
+}
+
+/* Received private message. This resolves the destination of the message
+ and sends the packet. This is used by both server and router. If the
+ destination is our locally connected client this sends the packet to
+ the client. This may also send the message for further routing if
+ the destination is not in our server (or router). */
+
+void silc_server_private_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcClientID *id;
+ SilcServerList *router;
+ SilcSocketConnection dst_sock;
+ SilcClientList *client;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!packet->dst_id) {
+ SILC_LOG_DEBUG(("Bad Client ID in private message packet"));
+ goto err;
+ }
+
+ /* Decode destination Client ID */
+ id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+ if (!id) {
+ SILC_LOG_DEBUG(("Could not decode destination Client ID"));
+ goto err;
+ }
+
+ /* If the destination belongs to our server we don't have to route
+ the message anywhere but to send it to the local destination. */
+ /* XXX: Should use local cache to search but the current idcache system
+ is so sucky that it cannot be used... it MUST be rewritten! Using
+ this search is probably faster than if we'd use here the current
+ idcache system. */
+ client = silc_idlist_find_client_by_id(server->local_list->clients, id);
+ if (client) {
+ /* It exists, now deliver the message to the destination */
+ dst_sock = (SilcSocketConnection)client->connection;
+
+ /* If we are router and the client has router then the client is in
+ our cell but not directly connected to us. */
+ if (server->server_type == SILC_ROUTER && client->router) {
+ silc_server_private_message_send_internal(server, dst_sock,
+ client->router, packet);
+ goto out;
+ }
+
+ /* Seems that client really is directly connected to us */
+ silc_server_private_message_send_local(server, dst_sock, client, packet);
+ goto out;
+ }
+
+ /* Destination belongs to someone not in this server. If we are normal
+ server our action is to send the packet to our router. */
+ if (server->server_type == SILC_SERVER && !server->standalone) {
+ router = server->id_entry->router;
+ dst_sock = (SilcSocketConnection)router->connection;
+
+ /* Send to primary route */
+ silc_server_private_message_send_internal(server, dst_sock, router,
+ packet);
+ goto out;
+ }
+
+ /* We are router and we will perform route lookup for the destination
+ and send the message to the correct route. */
+ if (server->server_type == SILC_ROUTER && !server->standalone) {
+
+ /* If we don't have specific route for the destination we will send
+ it to our primary route (default route). */
+ router = silc_server_route_check(id->ip.s_addr, server->id->port);
+ if (router) {
+ dst_sock = (SilcSocketConnection)router->connection;
+ } else {
+ router = server->id_entry->router;
+ dst_sock = (SilcSocketConnection)router->connection;
+ }
+
+ /* Send packet */
+ silc_server_private_message_send_internal(server, dst_sock,
+ router, packet);
+ goto out;
+ }
+
+ err:
+ silc_server_send_error(server, sock,
+ "No such nickname: Private message not sent");
+ out:
+ silc_buffer_free(buffer);
+}
+
+SilcChannelList *silc_find_channel(SilcServer server, SilcChannelID *id)
+{
+ int i;
+ SilcIDCache *id_cache;
+
+#define LCC(x) server->local_list->channel_cache[(x)]
+#define LCCC(x) server->local_list->channel_cache_count[(x)]
+
+ for (i = 0; i < 96; i++) {
+ if (LCC(i) == NULL)
+ continue;
+ if (silc_idcache_find_by_id(LCC(i), LCCC(i), (void *)id,
+ SILC_ID_CHANNEL, &id_cache))
+ return (SilcChannelList *)id_cache->context;
+ }
+
+ return NULL;
+#undef LCC
+#undef LCCC
+}
+
+/* Process received channel message. */
+
+void silc_server_channel_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcChannelList *channel = NULL;
+ SilcChannelID *id = NULL;
+ SilcClientID *sender;
+ SilcBuffer buffer = packet->buffer;
+
+ SILC_LOG_DEBUG(("Processing channel message"));
+
+ /* Check MAC */
+ if (!silc_server_packet_check_mac(server, sock, buffer))
+ goto out;
+
+ /* Sanity checks */
+ if (packet->dst_id_type != SILC_ID_CHANNEL) {
+ SILC_LOG_ERROR(("Received bad message for channel, dropped"));
+ SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
+ goto out;
+ }
+
+ /* Send to local clients */
+ id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel = silc_find_channel(server, id);
+ if (!channel) {
+ SILC_LOG_DEBUG(("Could not find channel"));
+ goto out;
+ }
+
+ /* Distribute the packet to our local clients. This will send the
+ packet for further routing as well, if needed. */
+ sender = silc_id_str2id(packet->src_id, packet->src_id_type);
+ silc_server_packet_relay_to_channel(server, sock, channel, sender,
+ packet->src_id_type,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ out:
+ silc_buffer_free(buffer);
+}
+
+/* Received channel key packet. We distribute the key to all of our locally
+ connected clients on the channel. Router ignores the packet. */
+
+void silc_server_channel_key(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcChannelKeyPayload payload = NULL;
+ SilcChannelID *id = NULL;
+ SilcChannelList *channel;
+ SilcClientList *client;
+ unsigned char *key;
+ unsigned int key_len;
+ char *cipher;
+ int i;
+
+ if (server->server_type == SILC_ROUTER)
+ goto out;
+
+ if (packet->src_id_type != SILC_ID_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ goto out;
+
+ /* Decode channel key payload */
+ payload = silc_channel_key_parse_payload(buffer);
+ if (!payload) {
+ SILC_LOG_ERROR(("Bad channel key payload, dropped"));
+ SILC_LOG_DEBUG(("Bad channel key payload, dropped"));
+ }
+
+ /* Get channel ID */
+ id = silc_id_str2id(silc_channel_key_get_id(payload, NULL), SILC_ID_CHANNEL);
+ if (!id)
+ goto out;
+
+ /* Get the channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
+ if (!channel) {
+ SILC_LOG_ERROR(("Received key for non-existent channel"));
+ SILC_LOG_DEBUG(("Received key for non-existent channel"));
+ goto out;
+ }
+
+ /* Save the key for us as well */
+ key = silc_channel_key_get_key(payload, &key_len);
+ if (!key)
+ goto out;
+ cipher = silc_channel_key_get_cipher(payload, NULL);;
+ if (!cipher)
+ goto out;
+ channel->key_len = key_len;
+ channel->key = silc_calloc(key_len, sizeof(unsigned char));
+ memcpy(channel->key, key, key_len);
+ silc_cipher_alloc(cipher, &channel->channel_key);
+ channel->channel_key->cipher->set_key(channel->channel_key->context,
+ key, key_len);
+
+ /* Distribute the key to all clients on the channel */
+ for (i = 0; i < channel->user_list_count; i++) {
+ client = channel->user_list[i].client;
+
+ if (client)
+ silc_server_packet_send_dest(server, client->connection,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ client->id, SILC_ID_CLIENT,
+ buffer->data, buffer->len, FALSE);
+ }
+
+ out:
+ if (id)
+ silc_free(id);
+ if (payload)
+ silc_channel_key_free_payload(payload);
+ silc_buffer_free(buffer);
+}
+
+/* Sends error message. Error messages may or may not have any
+ implications. */
+
+void silc_server_send_error(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...)
+{
+ va_list ap;
+ unsigned char buf[4096];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0,
+ buf, strlen(buf), FALSE);
+}
+
+/* Sends notify message */
+
+void silc_server_send_notify(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...)
+{
+ va_list ap;
+ unsigned char buf[4096];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0,
+ buf, strlen(buf), FALSE);
+}
+
+/* Sends notify message to a channel. The notify message sent is
+ distributed to all clients on the channel. */
+
+void silc_server_send_notify_to_channel(SilcServer server,
+ SilcChannelList *channel,
+ const char *fmt, ...)
+{
+ va_list ap;
+ unsigned char buf[4096];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ silc_server_packet_send_to_channel(server, channel, buf,
+ strlen(buf), FALSE);
+}
+
+/* Sends New ID Payload to remote end. The packet is used to distribute
+ information about new registered clients, servers, channel etc. usually
+ to routers so that they can keep these information up to date.
+ If the argument `broadcast' is TRUE then the packet is sent as
+ broadcast packet. */
+
+void silc_server_send_new_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *id, SilcIdType id_type,
+ unsigned int id_len)
+{
+ SilcBuffer packet;
+ unsigned char *id_string;
+
+ id_string = silc_id_id2str(id, id_type);
+ if (!id_string)
+ return;
+
+ packet = silc_buffer_alloc(2 + 2 + id_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(id_type),
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_UI_XNSTRING(id_string, id_len),
+ SILC_STR_END);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+ silc_free(id_string);
+ silc_buffer_free(packet);
+}
+
+/* Sends Replace ID payload to remote end. This is used to replace old
+ ID with new ID sent in the packet. This is called for example when
+ user changes nickname and we create new ID for the user. If the
+ argument `broadcast' is TRUE then the packet is sent as
+ broadcast packet. */
+/* XXX It would be expected that the new id is same type as the old
+ ID. :) */
+
+void silc_server_send_replace_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *old_id, SilcIdType old_id_type,
+ unsigned int old_id_len,
+ void *new_id, SilcIdType new_id_type,
+ unsigned int new_id_len)
+{
+ SilcBuffer packet;
+ unsigned char *oid;
+ unsigned char *nid;
+
+ oid = silc_id_id2str(old_id, old_id_type);
+ if (!oid)
+ return;
+
+ nid = silc_id_id2str(new_id, new_id_type);
+ if (!nid)
+ return;
+
+ packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(old_id_type),
+ SILC_STR_UI_SHORT(old_id_len),
+ SILC_STR_UI_XNSTRING(oid, old_id_len),
+ SILC_STR_UI_SHORT(new_id_type),
+ SILC_STR_UI_SHORT(new_id_len),
+ SILC_STR_UI_XNSTRING(nid, new_id_len),
+ SILC_STR_END);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+ silc_free(oid);
+ silc_free(nid);
+ silc_buffer_free(packet);
+}
+
+/* Creates new channel. */
+
+SilcChannelList *silc_server_new_channel(SilcServer server,
+ SilcServerID *router_id,
+ char *cipher, char *channel_name)
+{
+ int i, channel_len;
+ SilcChannelID *channel_id;
+ SilcChannelList *entry;
+ SilcCipher key;
+ unsigned char channel_key[32], *id_string;
+ SilcBuffer packet;
+
+ SILC_LOG_DEBUG(("Creating new channel"));
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+ /* Create channel key */
+ for (i = 0; i < 32; i++)
+ channel_key[i] = silc_rng_get_byte(server->rng);
+
+ if (!cipher)
+ cipher = "twofish";
+
+ /* Allocate keys */
+ silc_cipher_alloc(cipher, &key);
+ key->cipher->set_key(key->context, channel_key, 16);
+
+ /* Create the channel */
+ silc_id_create_channel_id(router_id, server->rng, &channel_id);
+ silc_idlist_add_channel(&server->local_list->channels, channel_name,
+ SILC_CHANNEL_MODE_NONE, channel_id, NULL, /*XXX*/
+ key, &entry);
+ LCCC(channel_name[0]) = silc_idcache_add(&LCC(channel_name[0]),
+ LCCC(channel_name[0]),
+ channel_name, SILC_ID_CHANNEL,
+ channel_id, (void *)entry);
+ entry->key = silc_calloc(16, sizeof(*entry->key));
+ entry->key_len = 16;
+ memcpy(entry->key, channel_key, 16);
+ memset(channel_key, 0, sizeof(channel_key));
+
+ /* Notify other routers about the new channel. We send the packet
+ to our primary route. */
+ if (server->standalone == FALSE) {
+ channel_len = strlen(channel_name);
+ id_string = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+ packet = silc_buffer_alloc(2 + SILC_ID_CHANNEL_LEN);
+
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(channel_len),
+ SILC_STR_UI_XNSTRING(channel_name, channel_len),
+ SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
+ SILC_STR_UI_XNSTRING(id_string, SILC_ID_CHANNEL_LEN),
+ SILC_STR_END);
+
+ /* Send the packet to our router. */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->id_entry->router->connection,
+ SILC_PACKET_NEW_CHANNEL_USER, 0,
+ packet->data, packet->len, TRUE);
+
+ silc_free(id_string);
+ silc_buffer_free(packet);
+ }
+
+#undef LCC
+#undef LCCC
+ return entry;
+}
+
+/* Create new client. This processes incoming NEW_CLIENT packet and creates
+ Client ID for the client and adds it to lists and cache. */
+
+SilcClientList *silc_server_new_client(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcClientList *id_entry;
+ char *username = NULL, *realname = NULL, *id_string;
+ SilcBuffer reply;
+
+ SILC_LOG_DEBUG(("Creating new client"));
+
+ if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+ return NULL;
+
+#define LCC(x) server->local_list->client_cache[(x) - 32]
+#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_STRING_ALLOC(&username),
+ SILC_STR_UI16_STRING_ALLOC(&realname),
+ SILC_STR_END);
+
+ /* Set the pointers to the client list and create new client ID */
+ id_entry = (SilcClientList *)sock->user_data;
+ id_entry->nickname = strdup(username);
+ id_entry->username = username;
+ id_entry->userinfo = realname;
+ silc_id_create_client_id(server->id, server->rng, server->md5hash,
+ username, &id_entry->id);
+
+ /* Add to client cache */
+ LCCC(username[0]) = silc_idcache_add(&LCC(username[0]),
+ LCCC(username[0]),
+ username, SILC_ID_CLIENT,
+ id_entry->id, (void *)id_entry);
+
+ /* Notify our router about new client on the SILC network */
+ if (!server->standalone)
+ silc_server_send_new_id(server, (SilcSocketConnection)
+ server->id_entry->router->connection,
+ server->server_type == SILC_SERVER ? TRUE : FALSE,
+ id_entry->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+
+ /* Send the new client ID to the client. */
+ id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
+ reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
+ silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
+ silc_buffer_format(reply,
+ SILC_STR_UI_SHORT(SILC_ID_CLIENT),
+ SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+ SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+ SILC_STR_END);
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0,
+ reply->data, reply->len, FALSE);
+ silc_free(id_string);
+ silc_buffer_free(reply);
+
+ /* Send some nice info to the client */
+ silc_server_send_notify(server, sock,
+ "Welcome to the SILC Network %s@%s",
+ username,
+ sock->hostname ? sock->hostname : sock->ip);
+ silc_server_send_notify(server, sock,
+ "Your host is %s, running version %s",
+ server->config->server_info->server_name,
+ server_version);
+ silc_server_send_notify(server, sock,
+ "Your connection is secured with %s cipher, "
+ "key length %d bits",
+ id_entry->send_key->cipher->name,
+ id_entry->send_key->cipher->key_len);
+ silc_server_send_notify(server, sock,
+ "Your current nickname is %s",
+ id_entry->nickname);
+
+ /* XXX Send motd */
+
+#undef LCC
+#undef LCCC
+ return id_entry;
+}
+
+/* Create new server. This processes incoming NEW_SERVER packet and
+ saves the received Server ID. The server is our locally connected
+ server thus we save all the information and save it to local list.
+ This funtion can be used by both normal server and router server.
+ If normal server uses this it means that its router has connected
+ to the server. If router uses this it means that one of the cell's
+ servers is connected to the router. */
+
+SilcServerList *silc_server_new_server(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcServerList *id_entry;
+ unsigned char *server_name, *id_string;
+
+ SILC_LOG_DEBUG(("Creating new server"));
+
+ if (sock->type != SILC_SOCKET_TYPE_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ return NULL;
+
+#define LSC(x) server->local_list->server_cache[(x) - 32]
+#define LSCC(x) server->local_list->server_cache_count[(x) - 32]
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_STRING_ALLOC(&id_string),
+ SILC_STR_UI16_STRING_ALLOC(&server_name),
+ SILC_STR_END);
+
+ /* Save ID and name */
+ id_entry = (SilcServerList *)sock->user_data;
+ id_entry->id = silc_id_str2id(id_string, SILC_ID_SERVER);
+ id_entry->server_name = server_name;
+
+ /* Add to server cache */
+ LSCC(server_name[0]) =
+ silc_idcache_add(&LSC(server_name[0]),
+ LSCC(server_name[0]),
+ server_name, SILC_ID_SERVER,
+ id_entry->id, (void *)id_entry);
+
+ /* Distribute the information about new server in the SILC network
+ to our router. If we are normal server we won't send anything
+ since this connection must be our router connection. */
+ if (server->server_type == SILC_ROUTER && !server->standalone)
+ silc_server_send_new_id(server, server->id_entry->router->connection,
+ TRUE, id_entry->id, SILC_ID_SERVER,
+ SILC_ID_SERVER_LEN);
+
+ silc_free(id_string);
+
+#undef LSC
+#undef LSCC
+ return id_entry;
+}
+
+/* Processes incoming New ID Payload. New ID Payload is used to distribute
+ information about newly registered clients, servers and created
+ channels. */
+
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIdType id_type;
+ unsigned char *id_string;
+ void *id;
+
+ SILC_LOG_DEBUG(("Processing new ID"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ server->server_type == SILC_SERVER)
+ return;
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&id_type),
+ SILC_STR_UI16_STRING_ALLOC(&id_string),
+ SILC_STR_END);
+
+ /* Normal server cannot have other normal server connections */
+ if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
+ goto out;
+
+ id = silc_id_str2id(id_string, id_type);
+ if (!id)
+ goto out;
+
+ /* XXX Do check whether the packet is coming outside the cell or
+ from someone inside the cell. If outside use global lists otherwise
+ local lists. */
+ /* XXX If using local list set the idlist->connection to the sender's
+ socket connection as it is used in packet sending */
+
+ switch(id_type) {
+ case SILC_ID_CLIENT:
+ {
+ SilcClientList *idlist;
+
+ /* Add the client to our local list. We are router and we keep
+ cell specific local database of all clients in the cell. */
+ silc_idlist_add_client(&server->local_list->clients, NULL, NULL, NULL,
+ id, sock->user_data, NULL, NULL,
+ NULL, NULL, &idlist);
+ idlist->connection = sock;
+ }
+ break;
+
+ case SILC_ID_SERVER:
+ {
+ SilcServerList *idlist;
+
+ /* Add the server to our local list. We are router and we keep
+ cell specific local database of all servers in the cell. */
+ silc_idlist_add_server(&server->local_list->servers, NULL, 0,
+ id, server->id_entry, NULL, NULL,
+ NULL, NULL, &idlist);
+ idlist->connection = sock;
+ }
+ break;
+
+ case SILC_ID_CHANNEL:
+ /* Add the channel to our local list. We are router and we keep
+ cell specific local database of all channels in the cell. */
+ silc_idlist_add_channel(&server->local_list->channels, NULL, 0,
+ id, server->id_entry, NULL, NULL);
+ break;
+
+ default:
+ goto out;
+ break;
+ }
+
+ out:
+ silc_free(id_string);
+}
--- /dev/null
+/*
+
+ server.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERVER_H
+#define SERVER_H
+
+/* Forward declaration for SILC Server object. The actual object is
+ defined in internal header file for server routines. I want to keep
+ the object private hence this declaration. */
+typedef struct SilcServerObjectStruct *SilcServer;
+
+#define SILC_SERVER_MAX_CONNECTIONS 10000
+
+/* General definitions */
+
+#define SILC_SERVER 0
+#define SILC_ROUTER 1
+
+/* Prototypes */
+int silc_server_alloc(SilcServer *new_server);
+void silc_server_free(SilcServer server);
+int silc_server_init(SilcServer server);
+void silc_server_run(SilcServer server);
+void silc_server_stop(SilcServer server);
+void silc_server_packet_send(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_send_dest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_forward(SilcServer server,
+ SilcSocketConnection sock,
+ unsigned char *data, unsigned int data_len,
+ int force_send);
+void silc_server_packet_send_to_channel(SilcServer server,
+ SilcChannelList *channel,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_relay_to_channel(SilcServer server,
+ SilcSocketConnection sender_sock,
+ SilcChannelList *channel,
+ void *sender,
+ SilcIdType sender_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_relay_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_close_connection(SilcServer server,
+ SilcSocketConnection sock);
+void silc_server_free_sock_user_data(SilcServer server,
+ SilcSocketConnection sock);
+void silc_server_remove_from_channels(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientList *client);
+void silc_server_disconnect_remote(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...);
+void silc_server_private_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_channel_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_channel_key(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_send_error(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...);
+void silc_server_send_notify(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...);
+void silc_server_send_notify_to_channel(SilcServer server,
+ SilcChannelList *channel,
+ const char *fmt, ...);
+void silc_server_send_new_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *id, SilcIdType id_type,
+ unsigned int id_len);
+void silc_server_send_replace_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *old_id, SilcIdType old_id_type,
+ unsigned int old_id_len,
+ void *new_id, SilcIdType new_id_type,
+ unsigned int new_id_len);
+SilcChannelList *silc_server_new_channel(SilcServer server,
+ SilcServerID *router_id,
+ char *cipher, char *channel_name);
+SilcClientList *silc_server_new_client(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+SilcServerList *silc_server_new_server(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+ SilcPacketContext *packet);
+
+#endif
--- /dev/null
+/*
+
+ server_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERVER_INTERNAL_H
+#define SERVER_INTERNAL_H
+
+/* Server statistics structure. This holds various statistics about
+ various things. */
+/* XXX TODO */
+typedef struct {
+
+} SilcServerStatistics;
+
+/*
+ SILC Server Object.
+
+*/
+typedef struct SilcServerObjectStruct {
+ char *server_name;
+ int server_type;
+ int sock;
+ int standalone;
+ int listenning;
+ SilcServerID *id;
+ SilcIdType id_type;
+ SilcServerList *id_entry;
+
+ /* SILC server task queues */
+ SilcTaskQueue io_queue;
+ SilcTaskQueue timeout_queue;
+ SilcTaskQueue generic_queue;
+
+ /* ID lists. */
+ SilcIDList local_list;
+ SilcIDList global_list;
+
+ /* Table of connected sockets */
+ SilcSocketConnection *sockets;
+
+ /* Server keys */
+ SilcCipher send_key;
+ SilcCipher receive_key;
+ SilcCipher none_cipher;
+
+ /* Server public key */
+ SilcPKCS public_key;
+
+ /* Hash objects for general hashing */
+ SilcHash md5hash;
+ SilcHash sha1hash;
+
+ /* HMAC objects for MAC's. */
+ SilcHmac md5hmac;
+ SilcHmac sha1hmac;
+
+ /* Configuration object */
+ SilcConfigServer config;
+
+ /* Random pool */
+ SilcRng rng;
+
+ /* Server statistics */
+ SilcServerStatistics stats;
+
+#ifdef SILC_SIM
+ /* SIM (SILC Module) table */
+ SilcSimContext **sim;
+ unsigned int sim_count;
+#endif
+} SilcServerObject;
+
+/* Macros */
+
+/* Registers generic task for file descriptor for reading from network and
+ writing to network. As being generic task the actual task is allocated
+ only once and after that the same task applies to all registered fd's. */
+#define SILC_REGISTER_CONNECTION_FOR_IO(fd) \
+do { \
+ SilcTask tmptask = silc_task_register(server->generic_queue, (fd), \
+ silc_server_packet_process, \
+ context, 0, 0, \
+ SILC_TASK_GENERIC, \
+ SILC_TASK_PRI_NORMAL); \
+ silc_task_set_iotype(tmptask, SILC_TASK_WRITE); \
+} while(0)
+
+#define SILC_SET_CONNECTION_FOR_INPUT(fd) \
+do { \
+ silc_schedule_set_listen_fd((fd), (1L << SILC_TASK_READ)); \
+} while(0)
+
+#define SILC_SET_CONNECTION_FOR_OUTPUT(fd) \
+do { \
+ silc_schedule_set_listen_fd((fd), ((1L << SILC_TASK_READ) | \
+ (1L << SILC_TASK_WRITE))); \
+} while(0)
+
+/* Prototypes */
+
+#endif
--- /dev/null
+/*
+
+ server_version.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+
+const char server_version[] = "27062000";
--- /dev/null
+/*
+
+ serverconfig.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* XXX
+ All possible configuration sections for SILC server.
+
+ <Cipher>
+
+ Format:
+
+ +<Cipher name>:<SIM path>
+
+ <PKCS>
+
+ Format:
+
+ +<PKCS name>:<key length>
+
+ <HashFunction>
+
+ Format:
+
+ +<Hash function name>:<SIM path>
+
+ <ServerInfo>
+
+ This section is used to set the server informations.
+
+ Format:
+
+ +<Server DNS name>:<Server IP>:<Geographic location>:<Port>
+
+ <AdminInfo>
+
+ This section is used to set the server's administrative information.
+
+ Format:
+
+ +<Location>:<Server type>:<Admin's name>:<Admin's email address>
+
+ <ListenPort>
+
+ This section is used to set ports the server is listenning.
+
+ Format:
+
+ +<Local IP/UNIX socket path>:<Remote IP>:<Port>
+
+ <Logging>
+
+ This section is used to set various logging files, their paths
+ and maximum sizes. All the other directives except those defined
+ below are ignored in this section. Log files are purged after they
+ reach the maximum set byte size.
+
+ Format:
+
+ +infologfile:<path>:<max byte size>
+ +errorlogfile:<path>:<max byte size>
+
+ <ConnectionClass>
+
+ This section is used to define connection classes. These can be
+ used to optimize the server and the connections.
+
+ Format:
+
+ +<Class number>:<Ping freq>:<Connect freq>:<Max links>
+
+ <ClientAuth>
+
+ This section is used to define client authentications.
+
+ Format:
+
+ +<Remote address or name>:<auth method>:<password/cert/key/???>:<Port>:<Class>
+
+ <AdminAuth>
+
+ This section is used to define the server's administration
+ authentications.
+
+ Format:
+
+ +<Hostname>:<auth method>:<password/cert/key/???>:<Nickname hash>:<Class>
+
+ <ServerConnection>
+
+ This section is used to define the server connections to this
+ server/router. Only routers can have normal server connections.
+ Normal servers leave this section epmty. The remote server cannot be
+ older than specified Version ID.
+
+ Format:
+
+ +<Remote address or name>:<auth method>:<password/key/???>:<Port>:<Version ID>:<Class>
+
+ <RouterConnection>
+
+ This section is used to define the router connections to this
+ server/router. Both normal server and router can have router
+ connections. Normal server usually has only one connection while
+ a router can have multiple. The remote server cannot be older than
+ specified Version ID.
+
+ Format:
+
+ +<Remote address or name>:<auth method>:<password/key/???>:<Port>:<Version ID>:<Class>
+
+ <DenyConnection>
+
+ This section is used to deny specific connections to your server. This
+ can be used to deny both clients and servers.
+
+ Format:
+
+ +<Remote address or name or nickname>:<Time interval>:<Comment>:<Port>
+
+ <RedirectClient>
+
+ This section is used to set the alternate servers that clients will be
+ redirected to when our server is full.
+
+ Format:
+
+ +<Remote address or name>:<Port>
+
+*/
+SilcConfigServerSection silc_config_server_sections[] = {
+ { "[Cipher]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 },
+ { "[PKCS]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 2 },
+ { "[HashFunction]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 },
+ { "[ServerInfo]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 },
+ { "[AdminInfo]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
+ { "[ListenPort]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
+ { "[Logging]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
+ { "[ConnectionClass]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, 4 },
+ { "[ClientConnection]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, 5 },
+ { "[ServerConnection]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, 6 },
+ { "[RouterConnection]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, 6 },
+ { "[AdminConnection]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 },
+ { "[DenyConnection]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 4 },
+ { "[RedirectClient]",
+ SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, 2 },
+
+ { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 }
+};
+
+/* Allocates a new configuration object, opens configuration file and
+ parses the file. The parsed data is returned to the newly allocated
+ configuration object. */
+
+SilcConfigServer silc_config_server_alloc(char *filename)
+{
+ SilcConfigServer new;
+ SilcBuffer buffer;
+ SilcConfigServerParse config_parse;
+
+ SILC_LOG_DEBUG(("Allocating new configuration object"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ fprintf(stderr, "Could not allocate new configuration object");
+ return NULL;
+ }
+
+ new->filename = filename;
+
+ /* Open configuration file and parse it */
+ config_parse = NULL;
+ buffer = NULL;
+ silc_config_open(filename, &buffer);
+ if (!buffer)
+ goto fail;
+ if ((silc_config_server_parse(new, buffer, &config_parse)) == FALSE)
+ goto fail;
+ if ((silc_config_server_parse_lines(new, config_parse)) == FALSE)
+ goto fail;
+
+ silc_free(buffer);
+
+ return new;
+
+ fail:
+ silc_free(new);
+ return NULL;
+}
+
+/* Free's a configuration object. */
+
+void silc_config_server_free(SilcConfigServer config)
+{
+ if (config) {
+ silc_free(config->filename);
+ silc_free(config->server_info);
+ silc_free(config->admin_info);
+ silc_free(config->listen_port);
+ silc_free(config->conn_class);
+ silc_free(config->clients);
+ silc_free(config->admins);
+ silc_free(config->servers);
+ silc_free(config->routers);
+ silc_free(config->denied);
+ silc_free(config->redirect);
+ silc_free(config);
+ }
+}
+
+/* Parses the the buffer and returns the parsed lines into return_config
+ argument. The return_config argument doesn't have to be initialized
+ before calling this. It will be initialized during the parsing. The
+ buffer sent as argument can be safely free'd after this function has
+ succesfully returned. */
+
+int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
+ SilcConfigServerParse *return_config)
+{
+ int i, begin;
+ unsigned int linenum;
+ char line[1024], *cp;
+ SilcConfigServerSection *cptr = NULL;
+ SilcConfigServerParse parse = *return_config, first = NULL;
+
+ SILC_LOG_DEBUG(("Parsing configuration file"));
+
+ begin = 0;
+ linenum = 0;
+ while((begin = silc_gets(line, sizeof(line),
+ buffer->data, buffer->len, begin)) != EOF) {
+ cp = line;
+ linenum++;
+
+ /* Check for bad line */
+ if (silc_check_line(cp))
+ continue;
+
+ /* Remove tabs and whitespaces from the line */
+ if (strchr(cp, '\t')) {
+ i = 0;
+ while(strchr(cp + i, '\t')) {
+ *strchr(cp + i, '\t') = ' ';
+ i++;
+ }
+ }
+ for (i = 0; i < strlen(cp); i++) {
+ if (cp[i] != ' ') {
+ if (i)
+ cp++;
+ break;
+ }
+ cp++;
+ }
+
+ /* Parse line */
+ switch(cp[0]) {
+ case '[':
+ /*
+ * Start of a section
+ */
+
+ /* Remove new line sign */
+ if (strchr(cp, '\n'))
+ *strchr(cp, '\n') = '\0';
+
+ /* Check for matching sections */
+ for (cptr = silc_config_server_sections; cptr->section; cptr++)
+ if (!strcmp(cp, cptr->section))
+ break;
+
+ if (!cptr->section) {
+ fprintf(stderr, "%s:%d: Unknown section `%s'\n",
+ config->filename, linenum, cp);
+ return FALSE;
+ }
+
+ break;
+ default:
+ /*
+ * Start of a configuration line
+ */
+
+ if (cptr->type != SILC_CONFIG_SERVER_SECTION_TYPE_NONE) {
+
+ if (strchr(cp, '\n'))
+ *strchr(cp, '\n') = ':';
+
+ if (parse == NULL) {
+ parse = silc_calloc(1, sizeof(*parse));
+ parse->line = NULL;
+ parse->section = NULL;
+ parse->next = NULL;
+ parse->prev = NULL;
+ } else {
+ if (parse->next == NULL) {
+ parse->next = silc_calloc(1, sizeof(*parse->next));
+ parse->next->line = NULL;
+ parse->next->section = NULL;
+ parse->next->next = NULL;
+ parse->next->prev = parse;
+ parse = parse->next;
+ }
+ }
+
+ if (first == NULL)
+ first = parse;
+
+ /* Add the line to parsing structure for further parsing. */
+ if (parse) {
+ parse->section = cptr;
+ parse->line = silc_buffer_alloc(strlen(cp) + 1);
+ parse->linenum = linenum;
+ silc_buffer_pull_tail(parse->line, strlen(cp));
+ silc_buffer_put(parse->line, cp, strlen(cp));
+ }
+ }
+ break;
+ }
+ }
+
+ /* Set the return_config argument to its first value so that further
+ parsing can be started from the first line. */
+ *return_config = first;
+
+ return TRUE;
+}
+
+/* Parses the lines earlier read from configuration file. The config object
+ must not be initialized, it will be initialized in this function. The
+ parse_config argument is uninitialized automatically during this
+ function. */
+
+int silc_config_server_parse_lines(SilcConfigServer config,
+ SilcConfigServerParse parse_config)
+{
+ int ret, check = FALSE;
+ unsigned int checkmask;
+ char *tmp;
+ SilcConfigServerParse pc = parse_config;
+ SilcBuffer line;
+
+ SILC_LOG_DEBUG(("Parsing configuration lines"));
+
+ if (!config)
+ return FALSE;
+
+ checkmask = 0;
+ while(pc) {
+ check = FALSE;
+ line = pc->line;
+
+ /* Get number of tokens in line */
+ ret = silc_config_check_num_token(line);
+ if (ret != pc->section->maxfields) {
+ /* Bad line */
+ fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
+ config->filename, pc->linenum, ret,
+ pc->section->maxfields);
+ break;
+ }
+
+ /* Parse the line */
+ switch(pc->section->type) {
+ case SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->cipher);
+
+ /* Get cipher name */
+ ret = silc_config_get_token(line, &config->cipher->alg_name);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Cipher name not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+
+ /* Get module name */
+ config->cipher->sim_name = NULL;
+ ret = silc_config_get_token(line, &config->cipher->sim_name);
+ if (ret < 0)
+ break;
+
+ /* Get block length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Cipher block length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->cipher->block_len = atoi(tmp);
+ silc_free(tmp);
+
+ /* Get key length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Cipher key length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->cipher->key_len = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_PKCS:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->pkcs);
+
+ /* Get PKCS name */
+ ret = silc_config_get_token(line, &config->pkcs->alg_name);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: PKCS name not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+
+ /* Get key length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: PKCS key length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->pkcs->key_len = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->hash_func);
+
+ /* Get Hash function name */
+ ret = silc_config_get_token(line, &config->hash_func->alg_name);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Hash function name not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+
+ /* Get Hash function module name */
+ config->hash_func->sim_name = NULL;
+ ret = silc_config_get_token(line, &config->hash_func->sim_name);
+ if (ret < 0)
+ break;
+
+ /* Get block length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Hash function block length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->hash_func->block_len = atoi(tmp);
+ silc_free(tmp);
+
+ /* Get hash length */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ config->hash_func->key_len = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO:
+
+ if (!config->server_info)
+ config->server_info = silc_calloc(1, sizeof(*config->server_info));
+
+ /* Get server name */
+ ret = silc_config_get_token(line, &config->server_info->server_name);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ /* Server name not defined */
+
+ }
+
+ /* Get server IP */
+ ret = silc_config_get_token(line, &config->server_info->server_ip);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ /* Server IP not defined */
+
+ }
+
+ /* Get server location */
+ ret = silc_config_get_token(line, &config->server_info->location);
+ if (ret < 0)
+ break;
+
+ /* Get server port */
+ /* XXX: Need port here??? */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ /* Port not defined */
+
+ }
+ config->server_info->port = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO:
+
+ if (!config->admin_info)
+ config->admin_info = silc_calloc(1, sizeof(*config->admin_info));
+
+ /* Get server type */
+ ret = silc_config_get_token(line, &config->admin_info->server_type);
+ if (ret < 0)
+ break;
+
+ /* Get admins name */
+ ret = silc_config_get_token(line, &config->admin_info->admin_name);
+ if (ret < 0)
+ break;
+
+ /* Get admins email address */
+ ret = silc_config_get_token(line, &config->admin_info->admin_email);
+ if (ret < 0)
+ break;
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
+
+ /* Get host */
+ ret = silc_config_get_token(line, &config->listen_port->host);
+ if (ret < 0)
+ break;
+
+ /* Get remote IP */
+ ret = silc_config_get_token(line, &config->listen_port->remote_ip);
+ if (ret < 0)
+ break;
+
+ /* Get port */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ /* Any port */
+ config->listen_port->port = 0;
+ } else {
+ config->listen_port->port = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
+
+ /* Get class number */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ /* Class number not defined */
+
+ }
+ config->conn_class->class = atoi(tmp);
+ silc_free(tmp);
+
+ /* Get ping frequency */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ config->conn_class->ping_freq = atoi(tmp);
+ silc_free(tmp);
+
+ /* Get connect frequency */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ config->conn_class->connect_freq = atoi(tmp);
+ silc_free(tmp);
+
+ /* Get max links */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ config->conn_class->max_links = atoi(tmp);
+ silc_free(tmp);
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->logging);
+
+ /* Get log section type and check it */
+ ret = silc_config_get_token(line, &config->logging->logtype);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Log file section not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+ if (strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_INFO)
+ && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_WARNING)
+ && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_ERROR)
+ && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
+ fprintf(stderr, "%s:%d: Unknown log file section '%s'\n",
+ config->filename, pc->linenum, config->logging->logtype);
+ break;
+ }
+
+ /* Get log filename */
+ ret = silc_config_get_token(line, &config->logging->filename);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ fprintf(stderr, "%s:%d: Log file name not defined\n",
+ config->filename, pc->linenum);
+ break;
+ }
+
+ /* Get max byte size */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->logging->maxsize = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->clients);
+
+ /* Get host */
+ ret = silc_config_get_token(line, &config->clients->host);
+ if (ret < 0)
+ break;
+ if (ret == 0)
+ /* Any host */
+ config->clients->host = strdup("*");
+
+ /* Get authentication method */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+ strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+ fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+ config->filename, pc->linenum, tmp);
+ break;
+ }
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+ config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+ config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+ silc_free(tmp);
+ }
+
+ /* Get authentication data */
+ ret = silc_config_get_token(line, &config->clients->auth_data);
+ if (ret < 0)
+ break;
+ if (ret == 0)
+ /* Any host */
+ config->clients->host = strdup("*");
+
+ /* Get port */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret == 0) {
+ config->clients->port = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ /* Get class number */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->clients->class = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->servers);
+
+ /* Get host */
+ ret = silc_config_get_token(line, &config->servers->host);
+ if (ret < 0)
+ break;
+ if (ret == 0)
+ /* Any host */
+ config->servers->host = strdup("*");
+
+ /* Get authentication method */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+ strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+ fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+ config->filename, pc->linenum, tmp);
+ break;
+ }
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+ config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+ config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+ silc_free(tmp);
+ }
+
+ /* Get authentication data */
+ ret = silc_config_get_token(line, &config->servers->auth_data);
+ if (ret < 0)
+ break;
+
+ /* Get port */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->servers->port = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ /* Get version */
+ ret = silc_config_get_token(line, &config->servers->version);
+ if (ret < 0)
+ break;
+
+ /* Get class number */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->servers->class = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->routers);
+
+ /* Get host */
+ ret = silc_config_get_token(line, &config->routers->host);
+ if (ret < 0)
+ break;
+ // if (ret == 0)
+ ///* Any host */
+ // config->routers->host = strdup("*");
+
+ /* Get authentication method */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+ strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+ fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+ config->filename, pc->linenum, tmp);
+ break;
+ }
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+ config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+ config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+ silc_free(tmp);
+ }
+
+ /* Get authentication data */
+ ret = silc_config_get_token(line, &config->routers->auth_data);
+ if (ret < 0)
+ break;
+
+ /* Get port */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->routers->port = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ /* Get version */
+ ret = silc_config_get_token(line, &config->routers->version);
+ if (ret < 0)
+ break;
+
+ /* Get class number */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->routers->class = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION:
+
+ SILC_SERVER_CONFIG_LIST_ALLOC(config->admins);
+
+ /* Get host */
+ ret = silc_config_get_token(line, &config->admins->host);
+ if (ret < 0)
+ break;
+ if (ret == 0)
+ /* Any host */
+ config->admins->host = strdup("*");
+
+ /* Get authentication method */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+ strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+ fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+ config->filename, pc->linenum, tmp);
+ break;
+ }
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+ config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+ if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+ config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+ silc_free(tmp);
+ }
+
+ /* Get authentication data */
+ ret = silc_config_get_token(line, &config->admins->auth_data);
+ if (ret < 0)
+ break;
+
+ /* Get nickname */
+ ret = silc_config_get_token(line, &config->admins->nickname);
+ if (ret < 0)
+ break;
+
+ /* Get class number */
+ ret = silc_config_get_token(line, &tmp);
+ if (ret < 0)
+ break;
+ if (ret) {
+ config->admins->class = atoi(tmp);
+ silc_free(tmp);
+ }
+
+ check = TRUE;
+ checkmask |= (1L << pc->section->type);
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
+ /* Not implemented yet */
+ check = TRUE;
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT:
+ /* Not implemented yet */
+ check = TRUE;
+ break;
+
+ case SILC_CONFIG_SERVER_SECTION_TYPE_NONE:
+ default:
+ /* Error */
+ break;
+ }
+
+ /* Check for error */
+ if (check == FALSE) {
+ /* Line could not be parsed */
+ fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
+ break;
+ }
+
+ pc = pc->next;
+ /* XXXX */
+ // silc_free(pc->prev);
+ // pc->prev = NULL;
+ }
+
+ if (check == FALSE)
+ return FALSE;;
+
+ /* Check that all mandatory sections really were found. If not, the server
+ cannot function and we return error. */
+ ret = silc_config_server_check_sections(checkmask);
+ if (ret == FALSE) {
+ /* XXX */
+
+ }
+
+ /* Before returning all the lists in the config object must be set
+ to their first values (the last value is first here). */
+ while (config->cipher && config->cipher->prev)
+ config->cipher = config->cipher->prev;
+ while (config->pkcs && config->pkcs->prev)
+ config->pkcs = config->pkcs->prev;
+ while (config->hash_func && config->hash_func->prev)
+ config->hash_func = config->hash_func->prev;
+ while (config->listen_port && config->listen_port->prev)
+ config->listen_port = config->listen_port->prev;
+ while (config->logging && config->logging->prev)
+ config->logging = config->logging->prev;
+ while (config->conn_class && config->conn_class->prev)
+ config->conn_class = config->conn_class->prev;
+ while (config->clients && config->clients->prev)
+ config->clients = config->clients->prev;
+ while (config->servers && config->servers->prev)
+ config->servers = config->servers->prev;
+ while (config->routers && config->routers->prev)
+ config->routers = config->routers->prev;
+
+ SILC_LOG_DEBUG(("Done"));
+
+ return TRUE;
+}
+
+/* This function checks that the mask sent as argument includes all the
+ sections that are mandatory in SILC server. */
+
+int silc_config_server_check_sections(unsigned int checkmask)
+{
+ if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) {
+
+ return FALSE;
+ }
+ if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO))) {
+
+ return FALSE;
+ }
+ if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT))) {
+
+ return FALSE;
+ }
+ if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
+
+ return FALSE;
+ }
+ if (!(checkmask
+ & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION))) {
+
+ return FALSE;
+ }
+ if (!(checkmask
+ & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION))) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Sets log files where log messages is saved by the server. */
+
+void silc_config_server_setlogfiles(SilcConfigServer config)
+{
+ SilcConfigServerSectionLogging *log;
+ char *info, *warning, *error, *fatal;
+ unsigned int info_size, warning_size, error_size, fatal_size;
+
+ SILC_LOG_DEBUG(("Setting configured log file names"));
+
+ /* Set default files before checking configuration */
+ info = SILC_LOG_FILE_INFO;
+ warning = SILC_LOG_FILE_WARNING;
+ error = SILC_LOG_FILE_ERROR;
+ fatal = SILC_LOG_FILE_FATAL;
+ info_size = 0;
+ warning_size = 0;
+ error_size = 0;
+ fatal_size = 0;
+
+ log = config->logging;
+ while(log) {
+ if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_INFO)) {
+ info = log->filename;
+ info_size = log->maxsize;
+ }
+ if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_WARNING)) {
+ warning = log->filename;
+ warning_size = log->maxsize;
+ }
+ if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_ERROR)) {
+ error = log->filename;
+ error_size = log->maxsize;
+ }
+ if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
+ fatal = log->filename;
+ fatal_size = log->maxsize;
+ }
+
+ log = log->next;
+ }
+
+ silc_log_set_files(info, info_size, warning, warning_size,
+ error, error_size, fatal, fatal_size);
+}
+
+/* Registers configured ciphers. These can then be allocated by the
+ server when needed. */
+
+void silc_config_server_register_ciphers(SilcConfigServer config)
+{
+ SilcConfigServerSectionAlg *alg;
+ SilcServer server = (SilcServer)config->server;
+
+ SILC_LOG_DEBUG(("Registering configured ciphers"));
+
+ alg = config->cipher;
+ while(alg) {
+
+ if (!alg->sim_name) {
+ /* Crypto module is supposed to be built in. Nothing to be done
+ here except to test that the cipher really is built in. */
+ SilcCipher tmp = NULL;
+
+ if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
+ SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
+ silc_server_stop(server);
+ exit(1);
+ }
+ silc_cipher_free(tmp);
+
+#ifdef SILC_SIM
+ } else {
+ /* Load (try at least) the crypto SIM module */
+ SilcCipherObject cipher;
+ SilcSimContext *sim;
+
+ memset(&cipher, 0, sizeof(cipher));
+ cipher.name = alg->alg_name;
+ cipher.block_len = alg->block_len;
+ cipher.key_len = alg->key_len * 8;
+
+ sim = silc_sim_alloc();
+ sim->type = SILC_SIM_CIPHER;
+ sim->libname = alg->sim_name;
+
+ if ((silc_sim_load(sim))) {
+ cipher.set_key =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_SET_KEY));
+ SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
+ cipher.set_key_with_string =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
+ SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
+ cipher.encrypt =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_ENCRYPT_CBC));
+ SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
+ cipher.decrypt =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_DECRYPT_CBC));
+ SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
+ cipher.context_len =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_CIPHER_SIM_CONTEXT_LEN));
+ SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
+
+ /* Put the SIM to the table of all SIM's in server */
+ server->sim = silc_realloc(server->sim,
+ sizeof(*server->sim) *
+ (server->sim_count + 1));
+ server->sim[server->sim_count] = sim;
+ server->sim_count++;
+ } else {
+ SILC_LOG_ERROR(("Error configuring ciphers"));
+ silc_server_stop(server);
+ exit(1);
+ }
+
+ /* Register the cipher */
+ silc_cipher_register(&cipher);
+#endif
+ }
+
+ alg = alg->next;
+ }
+}
+
+/* Registers configured PKCS's. */
+/* XXX: This really doesn't do anything now since we have statically
+ registered our PKCS's. This should be implemented when PKCS works
+ as SIM's. This checks now only that the PKCS user requested is
+ really out there. */
+
+void silc_config_server_register_pkcs(SilcConfigServer config)
+{
+ SilcConfigServerSectionAlg *alg = config->pkcs;
+ SilcServer server = (SilcServer)config->server;
+ SilcPKCS tmp = NULL;
+
+ SILC_LOG_DEBUG(("Registering configured PKCS"));
+
+ while(alg) {
+
+ if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
+ SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
+ silc_server_stop(server);
+ exit(1);
+ }
+ silc_free(tmp);
+
+ alg = alg->next;
+ }
+}
+
+/* Registers configured hash functions. These can then be allocated by the
+ server when needed. */
+
+void silc_config_server_register_hashfuncs(SilcConfigServer config)
+{
+ SilcConfigServerSectionAlg *alg;
+ SilcServer server = (SilcServer)config->server;
+
+ SILC_LOG_DEBUG(("Registering configured hash functions"));
+
+ alg = config->hash_func;
+ while(alg) {
+
+ if (!alg->sim_name) {
+ /* Hash module is supposed to be built in. Nothing to be done
+ here except to test that the hash function really is built in. */
+ SilcHash tmp = NULL;
+
+ if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
+ SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
+ silc_server_stop(server);
+ exit(1);
+ }
+ silc_free(tmp);
+
+#ifdef SILC_SIM
+ } else {
+ /* Load (try at least) the hash SIM module */
+ SilcHashObject hash;
+ SilcSimContext *sim;
+
+ memset(&hash, 0, sizeof(hash));
+ hash.name = alg->alg_name;
+ hash.block_len = alg->block_len;
+ hash.hash_len = alg->key_len;
+
+ sim = silc_sim_alloc();
+ sim->type = SILC_SIM_HASH;
+ sim->libname = alg->sim_name;
+
+ if ((silc_sim_load(sim))) {
+ hash.init =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_INIT));
+ SILC_LOG_DEBUG(("init=%p", hash.init));
+ hash.update =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_UPDATE));
+ SILC_LOG_DEBUG(("update=%p", hash.update));
+ hash.final =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_FINAL));
+ SILC_LOG_DEBUG(("final=%p", hash.final));
+ hash.context_len =
+ silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+ SILC_HASH_SIM_CONTEXT_LEN));
+ SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
+
+ /* Put the SIM to the table of all SIM's in server */
+ server->sim = silc_realloc(server->sim,
+ sizeof(*server->sim) *
+ (server->sim_count + 1));
+ server->sim[server->sim_count] = sim;
+ server->sim_count++;
+ } else {
+ SILC_LOG_ERROR(("Error configuring hash functions"));
+ silc_server_stop(server);
+ exit(1);
+ }
+
+ /* Register the cipher */
+ silc_hash_register(&hash);
+#endif
+ }
+
+ alg = alg->next;
+ }
+}
+
+/* Returns client authentication information from server configuration
+ by host (name or ip). */
+
+SilcConfigServerSectionClientConnection *
+silc_config_server_find_client_conn(SilcConfigServer config,
+ char *host, int port)
+{
+ int i;
+ SilcConfigServerSectionClientConnection *client = NULL;
+
+ if (!host)
+ return NULL;
+
+ if (!config->clients)
+ return NULL;
+
+ client = config->clients;
+
+ for (i = 0; client; i++) {
+ if (silc_string_compare(client->host, host))
+ break;
+ client = client->next;
+ }
+
+ if (!client)
+ return NULL;
+
+ return client;
+}
+
+/* Returns server connection info from server configuartion by host
+ (name or ip). */
+
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_server_conn(SilcConfigServer config,
+ char *host, int port)
+{
+ int i;
+ SilcConfigServerSectionServerConnection *serv = NULL;
+
+ if (!host)
+ return NULL;
+
+ if (!config->servers)
+ return NULL;
+
+ serv = config->servers;
+ for (i = 0; serv; i++) {
+ if (silc_string_compare(serv->host, host))
+ break;
+ serv = serv->next;
+ }
+
+ if (!serv)
+ return NULL;
+
+ return serv;
+}
+
+/* Returns router connection info from server configuartion by
+ host (name or ip). */
+
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_router_conn(SilcConfigServer config,
+ char *host, int port)
+{
+ int i;
+ SilcConfigServerSectionServerConnection *serv = NULL;
+
+ if (!host)
+ return NULL;
+
+ if (!config->routers)
+ return NULL;
+
+ serv = config->routers;
+ for (i = 0; serv; i++) {
+ if (silc_string_compare(serv->host, host))
+ break;
+ serv = serv->next;
+ }
+
+ if (!serv)
+ return NULL;
+
+ return serv;
+}
+
+/* Prints out example configuration file with default built in
+ configuration values. */
+
+void silc_config_server_print()
+{
+ char *buf;
+
+ buf = "\
+#\n\
+# Automatically generated example SILCd configuration file with default\n\
+# built in values. Use this as a guide to configure your SILCd configuration\n\
+# file for your system. For detailed description of different configuration\n\
+# sections refer to silcd(8) manual page.\n\
+#\n";
+ /*
+#<Cipher>
+#+blowfish
+#+twofish
+#+rc5
+#+rc6
+#+3des
+
+#<HashFunction>
+#+md5
+#+sha1
+
+<ServerInfo>
++lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+
+<AdminInfo>
++Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+<ListenPort>
++10.2.1.6:10.2.1.6:1333
+
+<Logging>
++infologfile:silcd.log:10000
+#+warninglogfile:/var/log/silcd_warning.log:10000
+#+errorlogfile:ERROR.log:10000
+#+fatallogfile:/var/log/silcd_error.log:
+
+<ConnectionClass>
+ +1:100:100:100
+ +2:200:300:400
+
+<ClientAuth>
++10.2.1.199:priikone:333:1
+
+<AdminAuth>
++10.2.1.199:priikone:priikone:1
+
+<ServerConnection>
+
+<RouterConnection>
+
+<DenyConnection>
+<RedirectClient>
+ */
+
+ fprintf(stdout, "%s\n", buf);
+}
--- /dev/null
+/*
+
+ serverconfig.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERVERCONFIG_H
+#define SERVERCONFIG_H
+
+/* Holds information of configured algorithms */
+typedef struct SilcConfigServerSectionAlgStruct {
+ char *alg_name;
+ char *sim_name;
+ unsigned int block_len;
+ unsigned int key_len;
+ struct SilcConfigServerSectionAlgStruct *next;
+ struct SilcConfigServerSectionAlgStruct *prev;
+#define SILC_CONFIG_SERVER_MODNAME "builtin"
+} SilcConfigServerSectionAlg;
+
+/* Holds server information from config file */
+typedef struct {
+ char *server_name;
+ char *server_ip;
+ char *location;
+ unsigned short port;
+} SilcConfigServerSectionServerInfo;
+
+/* Holds server's administrative information from config file */
+typedef struct {
+ char *server_type;
+ char *admin_name;
+ char *admin_email;
+} SilcConfigServerSectionAdminInfo;
+
+/* Holds all the ports the server is listenning on */
+typedef struct SilcConfigServerSectionListenPortStruct {
+ char *host;
+ char *remote_ip;
+ unsigned short port;
+ struct SilcConfigServerSectionListenPortStruct *next;
+ struct SilcConfigServerSectionListenPortStruct *prev;
+} SilcConfigServerSectionListenPort;
+
+/* Holds all the configured log files. */
+typedef struct SilcConfigServerSectionLoggingStruct {
+ char *logtype;
+ char *filename;
+ unsigned int maxsize;
+ struct SilcConfigServerSectionLoggingStruct *next;
+ struct SilcConfigServerSectionLoggingStruct *prev;
+
+/* Allowed <Logging> section types */
+#define SILC_CONFIG_SERVER_LF_INFO "infologfile"
+#define SILC_CONFIG_SERVER_LF_WARNING "warninglogfile"
+#define SILC_CONFIG_SERVER_LF_ERROR "errorlogfile"
+#define SILC_CONFIG_SERVER_LF_FATAL "fatalogfile"
+} SilcConfigServerSectionLogging;
+
+/* Holds all configured connection classes */
+typedef struct SilcConfigServerSectionConnectionClassStruct {
+ unsigned int class;
+ unsigned int ping_freq;
+ unsigned int connect_freq;
+ unsigned int max_links;
+ struct SilcConfigServerSectionConnectionClassStruct *next;
+ struct SilcConfigServerSectionConnectionClassStruct *prev;
+} SilcConfigServerSectionConnectionClass;
+
+#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
+#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
+
+/* Holds all client authentication data from config file */
+typedef struct SilcConfigServerSectionClientConnectionStruct {
+ char *host;
+ int auth_meth;
+ char *auth_data;
+ unsigned short port;
+ unsigned int class;
+ struct SilcConfigServerSectionClientConnectionStruct *next;
+ struct SilcConfigServerSectionClientConnectionStruct *prev;
+} SilcConfigServerSectionClientConnection;
+
+/* Hols all server's administrators authentication data from config file */
+typedef struct SilcConfigServerSectionAdminConnectionStruct {
+ char *host;
+ int auth_meth;
+ char *auth_data;
+ char *nickname;
+ unsigned int class;
+ struct SilcConfigServerSectionAdminConnectionStruct *next;
+ struct SilcConfigServerSectionAdminConnectionStruct *prev;
+} SilcConfigServerSectionAdminConnection;
+
+/* Holds all configured server/router connections from config file */
+typedef struct SilcConfigServerSectionServerConnectionStruct {
+ char *host;
+ int auth_meth;
+ char *auth_data;
+ unsigned short port;
+ char *version;
+ unsigned int class;
+ struct SilcConfigServerSectionServerConnectionStruct *next;
+ struct SilcConfigServerSectionServerConnectionStruct *prev;
+} SilcConfigServerSectionServerConnection;
+
+/* Holds all configured denied connections from config file */
+typedef struct {
+ char *host;
+ char *time;
+ char *comment;
+ unsigned short port;
+} SilcConfigServerSectionDenyConnection;
+
+/* Holds all client redirections from config file */
+typedef struct {
+ char *host;
+ unsigned short port;
+} SilcConfigServerSectionRedirectClient;
+
+/*
+ SILC Server Config object.
+
+ This object holds all the data parsed from the SILC server configuration
+ file. This is mainly used at the initialization of the server.
+
+*/
+typedef struct {
+ /* Pointer back to the server */
+ void *server;
+
+ /* Filename of the configuration file */
+ char *filename;
+
+ /* Configuration sections */
+ SilcConfigServerSectionAlg *cipher;
+ SilcConfigServerSectionAlg *pkcs;
+ SilcConfigServerSectionAlg *hash_func;
+ SilcConfigServerSectionServerInfo *server_info;
+ SilcConfigServerSectionAdminInfo *admin_info;
+ SilcConfigServerSectionListenPort *listen_port;
+ SilcConfigServerSectionLogging *logging;
+ SilcConfigServerSectionConnectionClass *conn_class;
+ SilcConfigServerSectionClientConnection *clients;
+ SilcConfigServerSectionServerConnection *servers;
+ SilcConfigServerSectionServerConnection *routers;
+ SilcConfigServerSectionAdminConnection *admins;
+ SilcConfigServerSectionDenyConnection *denied;
+ SilcConfigServerSectionRedirectClient *redirect;
+} SilcConfigServerObject;
+
+typedef SilcConfigServerObject *SilcConfigServer;
+
+/* Configuration section type enumerations. */
+typedef enum {
+ SILC_CONFIG_SERVER_SECTION_TYPE_NONE = 0,
+ SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER,
+ SILC_CONFIG_SERVER_SECTION_TYPE_PKCS,
+ SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION,
+ SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO,
+ SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO,
+ SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT,
+ SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING,
+ SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS,
+ SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION,
+ SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION,
+ SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION,
+ SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION,
+ SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION,
+ SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT,
+} SilcConfigServerSectionType;
+
+/* SILC Configuration Section structure. */
+typedef struct {
+ const char *section;
+ SilcConfigServerSectionType type;
+ unsigned int maxfields;
+} SilcConfigServerSection;
+
+/* LIst of all possible config sections in SILC server. */
+extern SilcConfigServerSection silc_config_server_sections[];
+
+/* Structure used in parsing the configuration lines. The line is read
+ from a file to this structure before parsing it further. */
+typedef struct SilcConfigServerParseStruct {
+ SilcBuffer line;
+ unsigned int linenum;
+ SilcConfigServerSection *section;
+ struct SilcConfigServerParseStruct *next;
+ struct SilcConfigServerParseStruct *prev;
+} *SilcConfigServerParse;
+
+/* Macros */
+
+/* Allocates list entries for configuration sections. Used by all
+ config sections as this is common. */
+#define SILC_SERVER_CONFIG_LIST_ALLOC(x) \
+do { \
+ if (!(x)) { \
+ (x) = silc_calloc(1, sizeof(*(x))); \
+ (x)->next = NULL; \
+ (x)->prev = NULL; \
+ } else { \
+ if (!(x)->next) { \
+ (x)->next = silc_calloc(1, sizeof(*(x)->next)); \
+ (x)->next->next = NULL; \
+ (x)->next->prev = (x); \
+ (x) = (x)->next; \
+ } \
+ } \
+} while(0)
+
+/* Prototypes */
+SilcConfigServer silc_config_server_alloc(char *filename);
+void silc_config_server_free(SilcConfigServer config);
+int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
+ SilcConfigServerParse *return_config);
+int silc_config_server_parse_lines(SilcConfigServer config,
+ SilcConfigServerParse parse_config);
+int silc_config_server_check_sections(unsigned int checkmask);
+void silc_config_server_setlogfiles(SilcConfigServer config);
+void silc_config_server_register_ciphers(SilcConfigServer config);
+void silc_config_server_register_pkcs(SilcConfigServer config);
+void silc_config_server_register_hashfuncs(SilcConfigServer config);
+SilcConfigServerSectionClientConnection *
+silc_config_server_find_client_conn(SilcConfigServer config,
+ char *host, int port);
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_server_conn(SilcConfigServer config,
+ char *host, int port);
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_router_conn(SilcConfigServer config,
+ char *host, int port);
+void silc_config_server_print();
+
+#endif
--- /dev/null
+/*
+
+ id.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+
+/* Creates a Server ID. Newly created Server ID is returned to the
+ new_id argument. */
+
+void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id)
+{
+ struct sockaddr_in server;
+ int rval, len;
+
+ SILC_LOG_DEBUG(("Creating new Server ID"));
+
+ *new_id = silc_calloc(1, sizeof(**new_id));
+ if (*new_id == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new Server ID"));
+ return;
+ }
+
+ /* Get IP address */
+ len = sizeof(server);
+ rval = getsockname(sock, (struct sockaddr *)&server, &len);
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Could not get IP address: %s", strerror(errno)));
+ silc_free(*new_id);
+ *new_id = NULL;
+ return;
+ }
+
+ /* Create the ID */
+ (*new_id)->ip = server.sin_addr;
+ (*new_id)->port = server.sin_port;
+ (*new_id)->rnd = silc_rng_get_rn16(rng);
+}
+
+/* Creates Client ID */
+
+void silc_id_create_client_id(SilcServerID *server_id, SilcRng rng,
+ SilcHash md5hash, char *nickname,
+ SilcClientID **new_id)
+{
+ unsigned char hash[16];
+
+ SILC_LOG_DEBUG(("Creating new Client ID"));
+
+ *new_id = silc_calloc(1, sizeof(**new_id));
+ if (*new_id == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new Client ID"));
+ return;
+ }
+
+ /* Create hash of the nickanem */
+ silc_hash_make(md5hash, nickname, strlen(nickname), hash);
+
+ /* Create the ID */
+ (*new_id)->ip.s_addr = server_id->ip.s_addr;
+ (*new_id)->rnd = silc_rng_get_byte(rng);
+ memcpy((*new_id)->hash, hash, CLIENTID_HASH_LEN);
+}
+
+/* Creates Channel ID */
+
+void silc_id_create_channel_id(SilcServerID *router_id, SilcRng rng,
+ SilcChannelID **new_id)
+{
+ SILC_LOG_DEBUG(("Creating new Channel ID"));
+
+ *new_id = silc_calloc(1, sizeof(**new_id));
+ if (*new_id == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new Channel ID"));
+ return;
+ }
+
+ /* Create the ID */
+ (*new_id)->ip.s_addr = router_id->ip.s_addr;
+ (*new_id)->port = router_id->port;
+ (*new_id)->rnd = silc_rng_get_rn16(rng);
+}
--- /dev/null
+/*
+
+ serverid.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERVERID_H
+#define SERVERID_H
+
+/* Prototypes */
+void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id);
+void silc_id_create_client_id(SilcServerID *server_id, SilcRng rng,
+ SilcHash md5hash, char *nickname,
+ SilcClientID **new_id);
+void silc_id_create_channel_id(SilcServerID *router_id, SilcRng rng,
+ SilcChannelID **new_id);
+
+#endif
--- /dev/null
+[Cipher]
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ServerInfo]
+silc.pspt.fi:193.166.51.47:Kuopio, Finland:1333
+
+[ListenPort]
+193.166.51.47:193.166.51.47:1333
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+#errorlogfile:ERROR.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+:::1333:1
+
+[AdminConnection]
+
+[ServerConnection]
+
+[RouterConnection]
+
+[DenyConnection]
+[RedirectClient]
--- /dev/null
+/*
+
+ silcd.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Created: Wed Mar 19 00:17:12 1997
+ *
+ * This is the main program for the SILC daemon. This parses command
+ * line arguments and creates the server object.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+#include "version.h"
+
+/* Long command line options */
+static struct option long_opts[] =
+{
+ { "config-file", 1, NULL, 'f' },
+ { "generate-config-file", 0, NULL, 'c' },
+ { "help", 0, NULL, 'h' },
+ { "version", 0, NULL,'V' },
+ { NULL, 0, NULL, 0 }
+};
+
+/* Prints out the usage of silc client */
+
+void silc_usage()
+{
+ printf("Usage: silcd [options]\n");
+ printf("Options:\n");
+ printf(" -f --config-file=FILE Alternate configuration file\n");
+ printf(" -c --generate-config-file Generate example configuration "
+ "file\n");
+ printf(" -h --help Display this message\n");
+ printf(" -V --version Display version\n");
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ int opt, option_index;
+ char *config_file = NULL;
+ SilcServer silcd;
+
+ /* Parse command line arguments */
+ if (argc > 1) {
+ while ((opt = getopt_long(argc, argv, "cf:hV",
+ long_opts, &option_index)) != EOF) {
+ switch(opt)
+ {
+ case 'h':
+ silc_usage();
+ break;
+ case 'V':
+ printf("SILCd Secure Internet Live Conferencing daemon, "
+ "version %s\n", silc_version);
+ printf("(c) 1997 - 2000 Pekka Riikonen "
+ "<priikone@poseidon.pspt.fi>\n");
+ exit(0);
+ break;
+ case 'c':
+ /* Print out example configuration file */
+ silc_config_server_print();
+ exit(0);
+ break;
+ case 'f':
+ config_file = strdup(optarg);
+ break;
+ default:
+ silc_usage();
+ break;
+ }
+ }
+ }
+
+ /* Default configuration file */
+ if (!config_file)
+ config_file = strdup(SILC_SERVER_CONFIG_FILE);
+
+ /* Create SILC Server object */
+ ret = silc_server_alloc(&silcd);
+ if (ret == FALSE)
+ goto fail;
+
+ /* Read configuration files */
+ silcd->config = silc_config_server_alloc(config_file);
+ if (silcd->config == NULL)
+ goto fail;
+
+ /* Initialize the server */
+ ret = silc_server_init(silcd);
+ if (ret == FALSE)
+ goto fail;
+
+ /* Run the server. When this returns the server has been stopped
+ and we will exit. */
+ silc_server_run(silcd);
+
+ /* Stop the server. This probably has been done already but it
+ doesn't hurt to do it here again. */
+ silc_server_stop(silcd);
+ silc_server_free(silcd);
+
+ exit(0);
+ fail:
+ exit(1);
+}
--- /dev/null
+/*
+
+ silcd.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCD_H
+#define SILCD_H
+
+/* Default server configuration file. This can be overridden at the
+ compilation time. Otherwise, use default. This can be overridden on
+ command line as well. */
+#ifndef SILC_SERVER_CONFIG_FILE
+#define SILC_SERVER_CONFIG_FILE "/etc/silc/silcd.conf\0"
+#endif
+
+void usage();
+
+char file_public_key[100]; /* server public key */
+char file_private_key[100]; /* server private key */
+
+#define PUBLICKEY_NAME "/silc_host_public"
+#define PRIVATEKEY_NAME "/silc_host_private"
+
+#define SERVER_KEY_EXPIRATION_DAYS 180
+int key_expires;
+
+#endif
--- /dev/null
+[Cipher]
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ServerInfo]
+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+
+[ListenPort]
+10.2.1.6:10.2.1.6:1333
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:silcd2_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+
+[ServerConnection]
+
+[RouterConnection]
+
+[DenyConnection]
+[RedirectClient]
--- /dev/null
+[Cipher]
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ServerInfo]
+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1334
+
+[ListenPort]
+10.2.1.6:10.2.1.6:1334
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:silcd2_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+10.2.1.199:passwd:priikone:priikone:1
+
+[ServerConnection]
+
+[RouterConnection]
+10.2.1.6:passwd:priikone:1333:1:1
+
+[DenyConnection]
+[RedirectClient]
--- /dev/null
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+# Please send patches to the Autoconf mailing list <autoconf@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .globl main
+ .ent main
+main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-cbm-sysv4
+ exit 0;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ arc64:OpenBSD:*:*)
+ echo mips64el-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hkmips:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ arm32:NetBSD:*:*)
+ echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ SR2?01:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:NetBSD:*:*)
+ echo powerpc-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ ${CC-cc} $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i?86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/6?? | 9000/7?? | 9000/80[024] | 9000/8?[136790] | 9000/892 )
+ sed 's/^ //' << EOF >$dummy.c
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (${CC-cc} $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+ rm -f $dummy.c $dummy
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE*:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ *9??*:MPE*:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i?86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo t3e-cray-unicosmk${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F300:UNIX_System_V:*:*)
+ FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ F301:UNIX_System_V:*:*)
+ echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ if test -x /usr/bin/objformat; then
+ if test "elf" = "`/usr/bin/objformat`"; then
+ echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
+ exit 0
+ fi
+ fi
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+# # uname on the ARM produces all sorts of strangeness, and we need to
+# # filter it out.
+# case "$UNAME_MACHINE" in
+# armv*) UNAME_MACHINE=$UNAME_MACHINE ;;
+# arm* | sa110*) UNAME_MACHINE="arm" ;;
+# esac
+
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us.
+ ld_help_string=`ld --help 2>&1`
+ ld_supported_emulations=`echo $ld_help_string \
+ | sed -ne '/supported emulations:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported emulations: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_emulations" in
+ i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
+ i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
+ sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ elf32arm) echo "${UNAME_MACHINE}-unknown-linux-gnu" ; exit 0 ;;
+ elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;;
+ esac
+
+ if test "${UNAME_MACHINE}" = "alpha" ; then
+ sed 's/^ //' <<EOF >$dummy.s
+ .globl main
+ .ent main
+ main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ LIBC=""
+ ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+
+ objdump --private-headers $dummy | \
+ grep ld.so.1 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+ elif test "${UNAME_MACHINE}" = "mips" ; then
+ cat >$dummy.c <<EOF
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+ printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+ printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ else
+ # Either a pre-BFD a.out linker (linux-gnuoldld)
+ # or one that does not give us useful --help.
+ # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+ # If ld does not provide *any* "supported emulations:"
+ # that means it is gnuoldld.
+ echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+ test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+ case "${UNAME_MACHINE}" in
+ i?86)
+ VENDOR=pc;
+ ;;
+ *)
+ VENDOR=unknown;
+ ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i?86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i?86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i?86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i?86:UnixWare:*:*)
+ if /bin/uname -X 2>/dev/null >/dev/null ; then
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ fi
+ echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION}
+ exit 0 ;;
+ pc:*:*:*)
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:*:6*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
--- /dev/null
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+ echo Configuration name missing. 1>&2
+ echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+ echo "or $0 ALIAS" 1>&2
+ echo where ALIAS is a recognized configuration type. 1>&2
+ exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+ *local*)
+ echo $1
+ exit 0
+ ;;
+ *)
+ ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ linux-gnu*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple)
+ os=
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+ | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+ | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \
+ | hppa2.0w \
+ | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
+ | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
+ | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+ | mipstx39 | mipstx39el | armv[34][lb] \
+ | sparc | sparclet | sparclite | sparc64 | v850)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i[34567]86)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+ | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
+ | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
+ | hppa2.0w-* \
+ | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
+ | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+ | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+ | sparc64-* | mips64-* | mipsel-* | armv[34][lb]-*\
+ | mips64el-* | mips64orion-* | mips64orionel-* \
+ | mipstx39-* | mipstx39el-* \
+ | f301-* | armv*-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-cbm
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-cbm
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-cbm
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [ctj]90-cray)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ os=-mpeix
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ os=-mpeix
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[34567]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i[34567]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i[34567]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i[34567]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netwinder)
+ basic_machine=armv4l-corel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | nexen)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | k6 | 6x86)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | nexen-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | k6-* | 6x86-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=rs6000-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ mips)
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sparc)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -rhapsody* \
+ | -openstep* | -mpeix* | -oskit*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-corel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f301-fujitsu)
+ os=-uxpv
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
--- /dev/null
+#
+# configure.in
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AC_INIT(includes/version.h)
+
+# Compiler settings
+CFLAGS="-Wall $CFLAGS"
+
+#
+# Put here any platform specific stuff
+#
+AC_CANONICAL_SYSTEM
+case "$target" in
+ *-*-linux*|*-*-mklinux*)
+ CFLAGS="-D_GNU_SOURCE $CFLAGS"
+ ;;
+ *)
+ ;;
+esac
+
+AM_INIT_AUTOMAKE(silc, 28062000)
+AC_PREREQ(2.3)
+AM_CONFIG_HEADER(includes/silcdefs.h)
+
+AC_PROG_CC
+AC_C_INLINE
+AC_C_CONST
+AC_ARG_PROGRAM
+
+AC_PROG_LN_S
+AC_SUBST(LN_S)
+
+# XXX
+# Compiler flags
+if test "$GCC"; then
+ CFLAGS="-finline-functions $CFLAGS"
+else
+ # Currently GCC is only supported compiler
+ AC_MSG_ERROR(GCC is only supported compiler currently)
+fi
+
+# Program checking
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_PROG_MAKE_SET
+
+# Header checking
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_HEADER_STAT
+
+# More header checking
+AC_CHECK_HEADERS(unistd.h string.h getopt.h errno.h fcntl.h assert.h)
+AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/time.h)
+AC_CHECK_HEADERS(netinet/in.h netinet/tcp.h netdb.h)
+AC_CHECK_HEADERS(pwd.h grp.h termcap.h)
+AC_CHECK_HEADERS(ncurses.h signal.h ctype.h)
+AC_CHECK_HEADERS(arpa/inet.h sys/mman.h)
+
+# Data type checking
+AC_TYPE_SIGNAL
+AC_TYPE_SIZE_T
+AC_TYPE_MODE_T
+AC_TYPE_UID_T
+AC_TYPE_PID_T
+
+# Function checking
+AC_CHECK_FUNCS(chmod stat fstat getenv putenv strerror ctime gettimeofday)
+AC_CHECK_FUNCS(getpid getgid getsid getpgid getpgrp getuid)
+AC_CHECK_FUNCS(strchr strstr strcpy strncpy memcpy memset memmove)
+AC_CHECK_FUNCS(gethostname gethostbyname gethostbyaddr)
+AC_CHECK_FUNCS(select socket listen bind shutdown close connect)
+AC_CHECK_FUNCS(fcntl setsockopt)
+AC_CHECK_FUNCS(getservbyname getservbyport)
+AC_CHECK_FUNCS(getopt_long time)
+AC_CHECK_FUNCS(mlock munlock)
+
+# SIM support checking
+# XXX These needs to be changed as more supported platforms appear.
+# XXX This probably needs to be made platform dependant check.
+AC_CHECKING(for SIM support)
+AC_CHECK_HEADERS(dlfcn.h,
+ AC_CHECK_LIB(dl, dlopen,
+ AC_DEFINE(SILC_SIM)
+ AC_MSG_RESULT(enabled SIM support)
+ LIBS="$LIBS -ldl",
+ AC_MSG_RESULT(no SIM support found)),
+ AC_MSG_RESULT(no SIM support found))
+
+# Debug checking
+AC_MSG_CHECKING(for enabled debugging)
+AC_ARG_ENABLE(debug,
+[ --enable-debug Enable debugging (warning: it is heavy!)],
+[ case "${enableval}" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(SILC_DEBUG)
+ CFLAGS="-O -g $CFLAGS"
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ CFLAGS="-O2 $CFLAGS"
+ ;;
+esac ], CFLAGS="-O2 $CFLAGS"
+ AC_MSG_RESULT(no))
+
+# XXX
+#LIBS="$LIBS -lefence"
+
+AC_ARG_WITH(silcd-config-file,
+[ --with-silcd-config-file[=PATH]
+ Use PATH as default configuration file in SILC
+ server.],
+[ AC_DEFINE_UNQUOTED(SILC_SERVER_CONFIG_FILE, "$withval") ])
+
+# Other configure scripts
+#AC_CONFIG_SUBDIRS(lib/zlib)
+AC_CONFIG_SUBDIRS(lib/silcmath/gmp-3.0.1)
+
+AC_OUTPUT( \
+Makefile
+doc/Makefile
+includes/Makefile
+lib/Makefile
+lib/silccore/Makefile
+lib/silccrypt/Makefile
+lib/silcmath/Makefile
+lib/silcsim/Makefile
+lib/silcsim/modules/Makefile
+lib/silcske/Makefile
+silc/Makefile
+silcd/Makefile)
--- /dev/null
+Coding Style in SILC source tree
+================================
+
+This documents describes the coding style and coding conventions used
+in the SILC source tree. The purpose of the document is to describe the
+common way to program for SILC and thus should be learned when programming
+new code. The document describes various conventions regarding variable
+naming, function naming, indentation, overall appearance of a piece of
+code and how some of the technical issues has been done in the SILC and
+should be done in the future.
+
+
+Naming
+======
+
+Generic naming
+
+All identifiers, whether they defines, functions or something else, with
+execption of variables, has a common naming convention. Usually all
+identifiers use `silc' prefix to indicate that the identifier is part of
+SILC distribution. For example, silc_server_init(), SILC_PACKET_TYPE_ERROR,
+etc. As mentioned however, variables, local or global, does not use this
+naming convention.
+
+Lower lever routines, usually some library routines, may use their
+own naming convention if generic API is defined over them. The API uses
+the common naming convention while the lower level routines uses what
+ever they want. For example, ciphers are implemented currently in this
+way. They define common SILC Cipher API but the actual implementation
+of algorithms uses their own naming convention. Another example is
+the GMP math library that uses its own function naming but we have our
+own SILC MP API over it that has been defined using common SILC naming
+convention.
+
+
+Variables
+
+Variable names are always in lowercase and any mixed-case or totally
+uppercase variable names should be avoided. Variable names may include
+underscore if it is necessary. For example, `unsigned char *id_string;'.
+
+The same name convention is used in structure field names. All fields
+in structures should be in lowercase. Global variables should have some
+sort of prefix to indicate that the variable is global. Although, global
+variables should be avoided if possible.
+
+Local variable names should be as short as possible without losing
+meaning of the name. For example there is no reason to call loop
+counter as `loop_counter' when `i' is commonly used instead. Using
+variable name `tmp' is also ok and should be used when some temporary
+value is used.
+
+
+#define's and Macros
+
+All #define's should always be in uppercase to indicate that it is
+a define, for example, `#define SILC_PACKET_TYPE_NONE 0'. As mentioned
+previously #define's and macros always use the `SILC' prefix. The
+names also uses always underscores.
+
+Names of #define's and macros should be self explanatory. This may
+lead to long names but it is better than having some `#define SILC_KE1_SX'
+which does not tell you anything.
+
+
+Type definitions
+
+Type definitions (typedefs) uses some what different naming convention
+from variables and macros. Typedefs has mixed-case names and they
+never use underscores. For example, `SilcSomeStruct', `SilcServerObject'.
+Like in any other case the names should be self explanatory which may
+lead to long names but that is not a problem.
+
+The names should tell what the typedef is about. If it is a typedef
+of a structure it should tell what the structure is for in the first
+place. For example `SilcClientStruct', `SilcCipherObject',
+`SilcConfigSection´, etc.
+
+
+Structures
+
+Same naming convention used in typedefs applies to names of structures as
+well. Same as with typedef, structure names should be self explanatory
+and should tell what the structure is made for.
+
+Structures are used a lot in SILC. They are used as simple structures
+and as objects as well. When normal structures are needed they are
+defined as follows,
+
+ struct SilcDummyStruct {
+ unsigned char *dummy;
+ };
+
+And used as `struct SilcDummyStruct *dummy'. However, this is quite
+rarely used in the SILC, instead structures are typedef'd as following
+later. When structure is used as object they are defined as follows,
+
+ typedef struct SilcDummyStruct {
+ unsigned char *dummy;
+ unsigned int flags;
+ void (*callback)(void *, unsigned int);
+ } SilcDummyObject;
+
+If the SilcDummyStruct is not needed it may be omitted (which is very
+common in SILC code), leaving,
+
+ typedef struct {
+ unsigned char *dummy;
+ unsigned int flags;
+ void (*callback)(void *, unsigned int);
+ } SilcDummyObject;
+
+Finally, it is common that structures are typedef'd pointers as they
+are very flexible to use,
+
+ typedef SilcDummyObject *SilcDummy;
+
+It is common in SILC to typedef structures instead of defining name
+for the structure. In this case the structure may be used without
+defining `struct' to the code, For example,
+
+ SilcDummyObject dummy_obj;
+ SilcDummyObject *dummy;
+
+If the structure has a pointer typedef then they are defined as normal
+variables but for real they are pointers, For example,
+
+ SilcDummy dummy;
+ dummy = silc_calloc(1, sizeof(*dummy));
+ dummy->flags = 0;
+
+This convention is very common in SILC code and has been used consistently
+throughout the code. The pattern here is that all structures are named
+as `SilcXxxStruct', all objects are named as `SilcXxxObject' and when
+they are typedef'd pointers they are named as `SilcXxx'.
+
+
+Functions
+
+Function naming uses the common naming convention used in the SILC. All
+functions are always lowercase and they use underscores. The name of
+the function always starts with prefix `silc_'. The name of the function
+should be self explanatory which may lead to long names. The name of
+a function is constructed from following parts,
+
+ silc_<application>_<module>_<function>
+
+The <application> is for example <client> or <server>, however, it is
+always omitted (and must be omitted) when programming library code.
+
+The <module> is the module you are programming currently. You should
+have a pretty good idea what you are programming and what the module
+does. For example, <cipher>, <config>, <command>, <packet>, etc.
+
+The <function> is the describtion of the functionality of the function
+you are writing. Naturally it should be self explanatory and weird
+short names should be avoided. It is better to have long function
+names than some odd name that does not tell what it is about. Function
+naming could be for example, <read>, <new_id>, <register>, <find_by_name>,
+etc.
+
+So, it is common in SILC to have function names, such as,
+
+ silc_server_packet_send
+ silc_server_packet_send_to_channel
+ silc_client_packet_process
+ silc_idcache_del_by_id
+ silc_task_unregister_by_fd
+ silc_protocol_excute_final
+ silc_buffer_alloc
+
+When function registers something the name of the function should
+generally be `silc_function_register' and unregistering should happen
+with `silc_function_unregister'. When function allocates something it
+should be called `silc_function_alloc' and when freeing it should be
+called `silc_function_free'. Respectively, with init/uninit functions.
+
+When this naming convention is used consistently it is easy to remember
+what the name of the function is. For example, if you need buffer it
+is easy to figure out that the routines are most likely called
+`silc_buffer_*', and if you need to allocate buffer it is most likely
+called `silc_buffer_alloc'. This sort of naming makes the programming,
+in the long run, much cleaner, simpler and faster.
+
+
+Inline functions
+
+SILC uses quite a bit inline functions to optimize the code. The
+naming of inline functions must follow same convention as any normal
+function. All inline functions in SILC are defined and written into
+header files. Inline functions must be defined in following manner
+in the header file,
+
+extern inline void silc_dummy_inline(unsigned int flags)
+{
+ doing_little_dummy_things;
+}
+
+Because the function is defined as extern they can be included into
+public header files. Do not forget to define inline function as extern.
+There are no any explicit prototype definitions for inline functions.
+
+
+Indentation
+===========
+
+SILC has been coded with Emacs so standard indentation of Emacs is used
+in the SILC code. The indentation is always 2 characters, not a
+tabulator. If you use Emacs then this should not be a problem. So,
+if you code for SILC be sure to format the code to the standard way
+used in the SILC before submitting the code.
+
+A tip for those who think that these long function names etc are just
+too long to type, consider using dynamic abbreviation found in Emacs.
+With this cool feature you only have type some part of the string and
+then use the dabbrev to find the rest of the string. I guess, by
+default it is M-/ in Emacs but I have binded it into Shift-TAB so it
+is fast to use when typing.
+
+
+Placing Braces
+==============
+
+The common fight about how the braces should be placed in the C code
+is probably going on in the SILC code as well. However, SILC code
+is consistent about this. The placing uses K&R style thus the opening
+of the brace is put to the last on the line and the closing brace is
+on first on its own line,
+
+ if (condition) {
+ silc_something();
+ silc_something_more();
+ }
+
+The function's braces are as follows,
+
+ int silc_client_function()
+ {
+ return 0;
+ }
+
+More examples,
+
+ if (condition) {
+ something;
+ silc_something_more();
+ } else {
+ something_else;
+ }
+
+ if (condition) {
+ something;
+ silc_something_more();
+ } else if (other_condition) {
+ something;
+ silc_something_more();
+ } else {
+ something_else;
+ }
+
+
+Commenting
+==========
+
+SILC code is usually pretty well commented and this should be the way
+in the future as well. However, the comments should not tell how the
+code works, it should be apparent by looking at the code. Instead the
+commenting should tell what the function does. All functions should
+be commented. If nothing more a line of comment telling what the function
+is about helps a lot when you go back to it after six months. Static
+functions should be commented as well.
+
+The commenting of functions in SILC has been made into the source files,
+and not in the header files where the function prototypes reside. Header
+files usually includes structure comments, macro comments and perhaps
+some other relevant commenting but usually not function comments.
+It is also Ok to comment the code inside function when it is needed.
+
+Comments should use normal C-language comments /* */ and not C++ comments.
+
+
+General Appearance
+==================
+
+The code should be clean and good to eye, although the function of it
+must always superseed the appearance. However, it is nice to read code
+that looks good. Here are some issues on general appearance.
+
+ o Use empty lines when appropriate but not too much. There
+ should not be excess empty lines at the end of file. However,
+ using some empty lines in the code makes the code better
+ looking.
+
+ o The line is 79 characters long and not one character longer.
+ Longer lines must be cut in two, or three, or ...
+
+ o Use spaces very much. Do not write things like `if(!k)',
+ instead write `if (!k)'. Same with `for', `while', etc.
+ Spaces should be put around all binary operators like `*',
+ `==', `+', etc. Also, when setting a value to variable be
+ sure to set spaces around `='. When writing argument list
+ to a function, space should follow each of the comma in the
+ list. However, do not use spaces with parenthesis, for
+ example, `if ( !k )' is not accepted.
+
+ o If you are not sure about how something should be done or
+ the code you've done is not finished, it should be commented
+ with XXX plus explanation what is going on.
+
+
+Source Files
+
+All source files starts with header that includes the name of the author,
+copyright notice and the copyright policy, usually part of GNU GPL licence.
+Now, if this really isn't that important but some sort of header should
+be in all source files.
+
+In the start of the source files should include the #include's that are
+needed. All library source files must include `silcincludes.h', this is
+a must. Client source file must include at least `clientincludes.h' and
+server source file must include `serverincludes.h'. Additional include's
+may be added as well, however, system specific includes should not be
+added directly (unless it is really a special case). Go see any source
+file as an example.
+
+
+Header Files
+
+As with source files, header files should include same file header at
+the start of the file.
+
+Header files are usually divided in three parts in SILC. At the start
+of header files should include all definitions, typedefs, structure
+definitions etc. After definitions should include macros and inline
+functions if any of those exist. After macros should include the
+public prototypes of the functions. Go see any header file as an example.
+
+
+Debug Messages
+==============
+
+When writing new code it is recommended that the code produces some sort
+of debug messages. SILC has own debug logging system that must be used
+in the generic SILC code. Few macros exist,
+
+ SILC_LOG_DEBUG
+ SILC_LOG_HEXDUMP
+ SILC_LOG_INFO
+ SILC_LOG_WARNING
+ SILC_LOG_ERROR
+ SILC_LOG_FATAL
+
+When doing debugging the most used macros are SILC_LOG_DEBUG and
+SILC_LOG_HEXDUMP. With first macro you can print out any sort of debug
+messages with variable argument list, for example,
+
+ SILC_LOG_DEBUG(("Start"));
+ SILC_LOG_DEBUG(("Packet length %d", packet_len));
+
+Note the extra parenthesis that are required for the macro so that the
+variable argument list formatting would work correctly.
+
+When you need to dump some data into screen you should use SILC_LOG_HEXDUMP
+macro. For example,
+
+ SILC_LOG_HEXDUMP(("Packet"), packet->data, packet->len);
+ SILC_LOG_HEXDUMP(("Packet, size %d", size), packet->data, packet->len);
+
+In SILC_LOG_HEXDUMP the data to be dumped are set between the second last
+and last parenthesis in order that the data is first and the length of the
+data is next. If arguments are used they are used the same way as in
+SILC_LOG_DEBUG and the data to be dumped are set after the argument list
+is closed with the parenthesis.
+
+
+Memory Allocation
+=================
+
+Naturally, memory allocation is a big part of SILC. However, there are
+few things that must be noted on the issue. SILC has defined its own
+memory allocation functions that must be used. System specific functions
+must not be used directly. There are functions like,
+
+ silc_malloc
+ silc_calloc
+ silc_realloc
+ silc_free
+
+You should always use silc_calloc instead of silc_malloc because
+silc_calloc automatically zeroes the allocated memory area. This is
+imporant especially with structures because generally we want that all
+fields, by default, are zero.
+
+So, instead of doing
+
+ SilcStruct *ptr;
+
+ ptr = silc_malloc(sizeof(*ptr));
+
+You should do
+
+ SilcStruct *ptr
+
+ ptr = silc_calloc(1, sizeof(*ptr));
+
+
+When freeing memory it should be zero'ed when appropriate. All memory
+allocations that handle sensitive data such as keys should be zero'ed
+by memset() before freeing the memory. Common way to do is,
+
+ memset(ptr, 'F', sizeof(*ptr));
+ silc_free(ptr);
+
+Where 'F' indicates free'd memory if you ever check it with debugger.
+Other choice is to use 0 instead of 'F'. The pointer after freeing
+should be set to NULL if appropriate, ptr = NULL.
+
+Note that some functions in the SILC library handles the zeroing of
+the memory area automatically, like for example, silc_buffer_free.
+
+
+Callback Programming
+====================
+
+SILC uses pretty much programming convention called callback programming.
+This is a programming style that extensively uses function pointers
+which are usually called inside some other function.
+
+Typical scenario is this; You are performing some task that most likely
+is asynchronous. You need to be able get some structure context when
+the operation finishes. Most common way in this case is to pass the
+structure context to the operation function with a callback function
+that is called when the operation has finished. Following code explains
+probaly better.
+
+
+/* Prototypes */
+static silc_callback(void *context);
+void silc_start();
+void silc_async_operation_register(int fd, SilcAsyncCb callback,
+ void *context);
+void silc_async_operation(int fd, SilcAsyncCb callback, void *context);
+
+/* Type definition of the callback function */
+typedef (*SilcAsyncCb)(void *context);
+
+/* Registers async operation and passes callback function and context
+ to it as arguments. */
+
+void silc_start()
+{
+ SilcDummyStruct *ctx;
+
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->fd = 30;
+
+ silc_async_operation_register(30, silc_callback, (void *)ctx);
+}
+
+/* The callblack function that is called from the operation function */
+
+static void silc_callback(void *context)
+{
+ SilcDummyStruct *ctx = (SilcDummyStruct *)context;
+
+ ctx->fd = 10;
+}
+
+/* Register async operation */
+
+void silc_async_operation_register(int fd, SilcAsyncCb callback,
+ void *context)
+{
+ /* Register and return immediately */
+ silc_register_async_operation_internal(fd, callback, context);
+}
+
+/* Operation function that will call the callback function after it
+ has finished. */
+
+void silc_async_operation(int fd, SilcAsyncCb callback, void *context)
+{
+ here_this_function_does_what_ever_it_wants;
+
+ here_something_more;
+
+ /* We are finished, call the callback */
+ if (callback)
+ (*callback)(context);
+}
+
+
+Now, after the registeration of the async operation in this dumb example
+the silc_start returns immediately. Lets say, 10 seconds later the
+async operation is executed (it would have been better to call it just
+timeout) by calling silc_async_operation which on the other hand will
+call the callback function after it has finished. The context that
+was passed to the registeration function is now passed back to the
+callback function. Thus, you will get the context you wanted. This is
+the typical scenario where callback functions come in very handy. This
+is also the best way to pass context's that are needed later without
+making them global context's. And as long as the context's are defined
+as void * they can be what ever contexts making the functions, that
+takes in the context, generic. Like in above example, you could pass
+what ever context to the registeration function if you'd want to.
+
+Callback programming is also used when making generic API's of some
+operation. For example, if you want generic hooks to the API so that
+something could be done while doing the operation (maybe to collect
+statistics or something else) just get the functions accept a callback
+function and context and call them when appropriate, then continue
+as normally.
+
+Callback functions has been used a lot in SILC code. The scheduler
+and task system implemented in core library uses extensively callback
+functions. Timeout's uses callbacks as well. SILC Key Exchange protocol
+uses callback functions too. The callback function in SKE provides
+packet sending without defining into the SKE code how the packets
+should be sent thus making it generic for both client and server
+(and actually to any application for that matter).
+
+There are some technical issues on callback programming that are
+common in SILC code.
+
+ o Callback functions are usually defined as void functions
+ as the routine that calls them usually don't care about
+ what the callback function does. Many times it doesn't
+ actually know what it does nor would it be interested to
+ know that. It doesn't care about return values.
+
+ o Many times the callback functions are static functions
+ because they are not wanted to be called in anyway else
+ than as callback functions.
+
+ o Callback function names usually have the `_cb' or `_callback'
+ at the end of function name, eg. silc_client_cb.
+
+ o Type of callback functions should be typedef'd instead of
+ defining them directly to the function. See above example.
+ This makes the code much cleaner.
+
+ o Callback function types has usually the suffix `Cb' or
+ ´Callback' in the type name, eg. SilcAsyncCallback.
+
+ o You must explicitly cast the void * context's to correct
+ type in the callback function. Of course you must be careful
+ to cast them to the correct type as they are void * they
+ could be anything. Many times this causes problems when you
+ forget what was the type you passed to it. Callback
+ programming may get very complex.
+
+ o You cannot use inline functions as callback functions,
+ naturally.
+
+Callback programming may be hard to understand from first standing if
+you haven't done these before, and debugging them may be pain in the
+ass sometimes. But after the grand idea behind callback functions
+becomes clear they are a wonderful tool.
+
+
+Copyrights of the Code
+======================
+
+The original code in SILC is GPL licensed. GMP is GPL licensed as well
+and zlib is with free license as well. New code will be accepted to
+the official SILC source tree if it is coded in GPL or similiar free
+license as GPL is, and of course if it is public domain. Code with
+restricting licenses will not be accepted to the SILC source tree.
+SILC is free software, open source, what ever, project and will remain
+as such.
+
+Also, about authoring; If you write code to SILC don't forget to add
+yourself as author at the start of the file. The reason for this is
+of course that everybody should get the credits they deserve but also
+if problems occur we know who to blame. :)
--- /dev/null
+Frequently Asked Questions
+
+
+Q: What is SILC?
+A: SILC (Secure Internet Live Conferencing) is a protocol which provides
+ secure conferencing services in the Internet over insecure channel.
+ SILC is IRC like although internally they are very different. Biggest
+ similiarity between SILC and IRC is that they both provide conferencing
+ services and that SILC has almost same commands as IRC. Other than
+ that they are nothing alike.
+
+ Biggest differences are that SILC is secure what IRC is not in any
+ way. The network model is also entirely different compared to IRC.
+
+
+Q: Can I use SILC with IRC client? What about can I use IRC with SILC
+ client?
+A: Answer for both question is no. IRC client is in no way compatible
+ with SILC server. SILC client cannot currenly use IRC but this may
+ change in the future if IRC support is added to the SILC client.
+ After that one could use both SILC and IRC with the same client.
+ Although, even then one cannot talk from SILC network to IRC network.
+ That just is not possible.
+
+
+Q: How secure SILC really is?
+A: A good question which I don't have a answer. SILC has been tried to
+ make as secure as possible. However, there is no security protocol
+ or security software that has not been vulnerable to some sort of
+ attacks. SILC is in no means different from this. So, it is suspected
+ that there are security holes in the SILC. These holes just needs to
+ be found so that they can be fixed.
+
+ But to give you some parameters of security SILC uses the most secure
+ crytographic algorithms such as Blowfish, RC5, Twofish, etc. SILC
+ does not have DES or 3DES as DES is insecure and 3DES is just too
+ slow. SILC also uses cryptographically strong random number generator
+ when it needs random numbers. Public key cryptography uses RSA
+ and Diffie Hellman algorithms. Key lengths for ciphers are initially
+ set to 128 bits but many algorithm supports longer keys. For public
+ key algorithms the starting key length is 1024 bits.
+
+ But the best answer for this question is that SILC is as secure as
+ its weakest link. SILC is open and the protocol is open and in public
+ thus open for security analyzes.
+
+ To give a list of attacks that are ineffective against SILC:
+
+ o Man-in-the-middle attacks are ineffective if proper public key
+ infrastructure is used. SILC is vulnerable to this attack if
+ the public keys used in the SILC are not verified to be trusted.
+
+ o IP spoofing is ineffective (because of encryption and trusted
+ server keys).
+
+ o Attacks that change the contents of the data or add extra
+ data to the packets are ineffective (because of encryption and
+ integrity checks).
+
+ o Passive attacks (listenning network traffic) are ineffective
+ (because of encryption). Everything is encrypted including
+ authentication data such as passwords when they are needed.
+
+ o Any sort of cryptanalytic attacks are tried to make ineffective
+ by using the best cryptographic algorithms out there.
+
+
+Q: Why SILC? Why not IRC3?
+A: Question that is justified no doubt of that. I didn't start doing SILC
+ to be replacement for IRC. SILC was something that didn't exist in
+ 1996 or even today except that SILC is now released. However, I did
+ check out the IRC3 project in 1997 when I started coding and planning
+ the SILC protocol.
+
+ But, IRC3 is problematic. Why? Because it still doesn't exist. The
+ project is at the same spot where it was in 1997 when I checked it out.
+ And it was old project back then as well. Couple of months ago I
+ checked it again and nothing were happening. That's the problem of IRC3
+ project. The same almost to happened to SILC as well as I wasn't making
+ real progress over the years. I talked to the original author of IRC,
+ Jarkko Oikarinen, in 1997 and he directed me to the IRC3 project,
+ although he said that IRC3 is a lot of talking and not that much of
+ anything else. I am not trying to put down the IRC3 project but its
+ problem is that no one in the project is able to make a decision what
+ is the best way to go about making the IRC3 and I wasn't going to be
+ part of that. The fact is that if I would've gone to IRC3 project,
+ nor IRC3 or SILC would exist today. I think IRC3 could be something
+ really great if they just would get their act together and start
+ coding the thing. I hope that the release of SILC gives a boost to
+ the IRC3 project as well.
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+all:
+ touch draft-riikonen-silc-spec-00.txt
+ touch draft-riikonen-silc-pp-00.txt
+ touch draft-riikonen-silc-ke-auth-00.txt
+ -cd ..
+
+dist-hook:
+ -rm -f draft-riikonen*.txt
+ ./makerfc draft-riikonen-silc-spec-00.nroff \
+ draft-riikonen-silc-spec-00.txt
+ ./makerfc draft-riikonen-silc-pp-00.nroff \
+ draft-riikonen-silc-pp-00.txt
+ ./makerfc draft-riikonen-silc-ke-auth-00.nroff \
+ draft-riikonen-silc-ke-auth-00.txt
+
+EXTRA_DIST = \
+ CodingStyle \
+ example_silcd.conf \
+ example_silc.conf \
+ draft-riikonen*.txt
--- /dev/null
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+EXTRA_DIST = \
+ CodingStyle \
+ example_silcd.conf \
+ example_silc.conf \
+ draft-riikonen*.txt
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../includes/silcdefs.h
+CONFIG_CLEAN_FILES =
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = doc
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file; \
+ done
+ $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+info:
+dvi:
+check: all
+ $(MAKE)
+installcheck:
+install-exec:
+ @$(NORMAL_INSTALL)
+
+install-data:
+ @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+ @:
+
+uninstall:
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(DISTCLEANFILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-generic
+
+clean: clean-generic mostlyclean
+
+distclean: distclean-generic clean
+ -rm -f config.status
+
+maintainer-clean: maintainer-clean-generic distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+all:
+ touch draft-riikonen-silc-spec-00.txt
+ touch draft-riikonen-silc-pp-00.txt
+ touch draft-riikonen-silc-ke-auth-00.txt
+ -cd ..
+
+dist-hook:
+ -rm -f draft-riikonen*.txt
+ ./makerfc draft-riikonen-silc-spec-00.nroff \
+ draft-riikonen-silc-spec-00.txt
+ ./makerfc draft-riikonen-silc-pp-00.nroff \
+ draft-riikonen-silc-pp-00.txt
+ ./makerfc draft-riikonen-silc-ke-auth-00.nroff \
+ draft-riikonen-silc-ke-auth-00.txt
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 27 June 2000
+.ds CH Key Exchange and Authentication
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group P. Riikonen
+Internet-Draft
+draft-riikonen-silc-ke-auth-00.txt 27 June 2000
+Expires: 27 Jan 2001
+
+.in 3
+
+.ce
+SILC Key Exchange and Authentication Protocols
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other
+documents at any time. It is inappropriate to use Internet-Drafts
+as reference material or to cite them other than as
+``work in progress.''
+
+To learn the current status of any Internet-Draft, please check the
+``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes two protocols used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification internet-draft [SILC1]. The
+SILC Key Exchange (SKE) protocol provides secure key exchange between
+two parties resulting into shared secret key material. The protocol
+is based on Diffie Hellman key exchange algorithm and its functionality
+is derived from several key exchange protocols. SKE uses best parts
+of the SSH2 Key Exchange protocol, Station-To-Station (STS) protocol
+and the OAKLEY Key Determination protocol [OAKLEY].
+
+The SILC Connection Authentication protocol provides user level
+authentication used when creating connections in SILC network. The
+protocol is transparent to the authentication data which means that it
+can be used to authenticate the user with, for example, passphrase
+(pre-shared- secret) or public key (and certificate).
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction .................................................. 2
+2 SILC Key Exchange Protocol .................................... 3
+ 2.1 Key Exchange Payloads ..................................... 3
+ 2.1.1 Key Exchange Start Payload .......................... 4
+ 2.1.2 Key Exchange 1 Payload .............................. 7
+ 2.1.3 Key Exchange 2 Payload .............................. 9
+ 2.2 Key Exchange Procedure .................................... 10
+ 2.3 Processing the Key Material ............................... 12
+ 2.4 SILC Key Exchange Groups .................................. 13
+ 2.4.1 diffie-hellman-group1 ............................... 13
+ 2.4.2 diffie-hellman-group2 ............................... 14
+ 2.5 Key Exchange Status Types ................................. 14
+3 SILC Connection Authentication Protocol ....................... 16
+ 3.1 Connection Auth Payload ................................... 17
+ 3.2 Connection Authentication Types ........................... 18
+ 3.2.1 Passphrase Authentication ........................... 18
+ 3.2.2 Public Key Authentication ........................... 18
+ 3.3 Connection Authentication Status Types .................... 19
+4 Security Considerations ....................................... 19
+5 References .................................................... 19
+6 Author's Address .............................................. 20
+
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1: Key Exchange Start Payload
+Figure 2: Key Exchange 1 Payload
+Figure 3: Key Exchange 2 Payload
+Figure 4: Connection Auth Payload
+
+
+.ti 0
+1 Introduction
+
+This memo describes two protocols used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification internet-draft [SILC1]. The
+SILC Key Exchange (SKE) protocol provides secure key exchange between
+two parties resulting into shared secret key material. The protocol
+is based on Diffie Hellman key exchange algorithm and its functionality
+is derived from several key exchange protocols. SKE uses best parts
+of the SSH2 Key Exchange protocol, Station-To-Station (STS) protocol
+and the OAKLEY Key Determination protocol.
+
+The SILC Connection Authentication protocol provides user level
+authentication used when creating connections in SILC network. The
+protocol is transparent to the authentication data which means that it
+can be used to authenticate the user with, for example, passphrase
+(pre-shared- secret) or public key (and certificate).
+
+The basis of secure SILC session requires strong and secure key exchange
+protocol and authentication. The authentication protocol is entirely
+secured and no authentication data is ever sent in the network without
+encrypting and authenticating it first. Thus, authentication protocol
+may be used only after the key exchange protocol has been successfully
+completed.
+
+This document refers constantly to other SILC protocol specification
+Internet Drafts that are a must read for those who wants to understand
+the function of these protocols. The most important references are
+the Secure Internet Live Conferencing, Protocol Specification [SILC1]
+and SILC Packet Protocol [SILC2] Internet Drafts.
+
+The protocol is intended to be used with the SILC protocol thus it
+does not define own framework that could be used. The framework is
+provided by the SILC protocol.
+
+
+.ti 0
+2 SILC Key Exchange Protocol
+
+SILC Key Exchange Protocol (SKE) is used to exchange shared secret
+between connecting entities. The result of this protocol is a key
+material used to secure the communication channel. The protocol uses
+Diffie-Hellman key exchange algorithm and its functionality is derived
+from several key exchange protocols. SKE uses best parts of the SSH2
+Key Exchange protocol, Station-To-Station (STS) protocol and the OAKLEY
+Key Determination protocol. The protocol does not claim any conformance
+to any of these protocols, they were merely used as a reference when
+designing this protocol.
+
+The purpose of SILC Key Exchange protocol is to create session keys to
+be used in current SILC session. The keys are valid only for some period
+of time (usually an hour) or at most until the session ends. These keys
+are used to protect packets like commands, command replies and other
+communication between two entities. If connection is server to server
+connection, the keys are used to protect all traffic between those
+servers. In client connections usually all the packets are protected
+with this key except channel messages; channels has their own keys and
+they are not exchanged with this protocol.
+
+
+.ti 0
+2.1 Key Exchange Payloads
+
+During the key exchange procedure public data is sent between initiator
+and responder. This data is later used in the key exchange procedure.
+There are several payloads used in the key exchange. As for all SILC
+packets, SILC Packet Header, described in [SILC2], is at the start of all
+packets, the same is done with these payloads as well. All fields in
+all payloads are always in MSB (most significant byte first) order.
+Following descriptions of these payloads.
+
+
+.ti 0
+2.1.1 Key Exchange Start Payload
+
+Key exchange between two entities always begins with a
+SILC_PACKET_KEY_EXCHANGE packet containing Key Exchange Start Payload.
+When performing key exchange between client and server, the client sends
+Key Exchange Start Payload to server filled with all security properties
+that the client supports. Server then checks if it supports the security
+properties.
+
+It then sends a Key Exchange Start Payload to client filled with security
+properties it selected from the payload client originally sent. The
+payload sent by server must include only one chosen property per list.
+
+When performing key exchange between server and server, the server who
+is contacting sends the Key Exchange Start Payload with security property
+list it supports to the other server. The contacted party then chooses
+the preferred properties same way as previously described. It then
+replies with the properties it wanted same way as previously described.
+
+The Key Exchange Start Payload is used to tell connecting entities what
+security properties and algorithms should be used in the communication.
+If perfect forward secrecy (PFS) is not desired (PFS is undefined by
+default) Key Exchange Start Payload is sent only once per session, thus,
+for example, re-keying will not cause sending of a new payload. If PFS
+is desired, re-keying will always cause new key exchange thus causes
+sending of a new Key Exchange Start Payload.
+
+When performing first key exchange this payload is never encrypted, as
+there are no existing keys to encrypt it with. If performing re-keying
+(PFS was selected) this payload is encrypted with the existing key and
+encryption algorithm.
+
+Cookie is also send in this payload. Cookie is used to uniform the
+payload so that none of the key exchange parties cannot determine this
+payload before hand. The cookie must be returned to the original sender
+by the responder.
+
+Following diagram represents the Key Exchange Start Payload. The lists
+mentioned below are always comma (`,') separated and the list must
+not include spaces (` ').
+
+
+
+
+
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| RESERVED | Flags | Payload Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
++ +
+| |
++ Cookie +
+| |
++ +
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Key Exchange Grp Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Key Exchange Groups ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| PKCS Alg Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ PKCS Algorithms ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Encryption Alg Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Encryption Algorithms ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Hash Alg Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Hash Algorithms ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Compression Alg Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Compression Algorithms ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 1: Key Exchange Start Payload
+
+
+
+.in 6
+o RESERVED (1 byte) - Reserved field. Sender fills this with
+ zeroes (0).
+
+o Flags (1 byte) - Indicates flags to be used in the key
+ exchange. Several flags can be set at once by ORing the
+ flags together. Following flags are reserved for this field.
+
+ No flags 0x00
+
+ In this case the field is ignored.
+
+ No Reply 0x01
+
+ If set the receiver of the payload does not reply to
+ the packet.
+
+ PFS 0x02
+
+ Perfect Forward Secrecy (PFS) to be used in the
+ key exchange protocol. If not set, re-keying
+ is performed using the old key. When PFS is used,
+ re-keying and creating new keys for any particular
+ purpose will cause new key exchange.
+
+ Rest of the flags are reserved for the future and
+ must not be set.
+
+o Payload Length (2 bytes) - Length of the entire Key Exchange
+ Start payload.
+
+o Cookie (16 bytes) - Cookie that uniforms this payload so
+ that each of the party cannot determine the payload before
+ hand.
+
+o Key Exchange Grp Length (2 bytes) - The length of the
+ key exchange group list, including this field as well.
+
+o Key Exchange Group (variable length) - The list of
+ key exchange groups. See the section 2.1.2 SILC Key Exchange
+ Groups for definitions of these groups.
+
+o PKCS Alg Length (2 bytes) - The length of the PKCS algorithms
+ list, including this field as well.
+
+o PKCS Algorithms (variable length) - The list of PKCS
+ algorithms.
+
+o Encryption Alg Length (2 bytes) - The length of the encryption
+ algorithms list, including this field as well.
+
+o Encryption Algorithms (variable length) - The list of
+ encryption algorithms.
+
+o Hash Alg Length (2 bytes) - The length of the Hash algorithms
+ list, including this field as well.
+
+o Hash Algorithms (variable length) - The list of Hash algorithms.
+
+o Compression Alg Length (2 bytes) - The length of the
+ compression algorithms list, including this field as well.
+
+o Compression Algorithms (variable length) - The list of
+ compression algorithms.
+.in 3
+
+
+.ti 0
+2.1.2 Key Exchange 1 Payload
+
+Key Exchange 1 Payload is used to deliver computed public data from
+initiator to responder. This data is used to compute the shared secret,
+later by all parties. Key Exchange 1 Payload is only sent after the
+SILC_PACKET_KEY_EXCHANGE packet and the Key Exchange Start Payload has
+been processed by all the parties.
+
+This payload sends the initiator's public key to the responder. Responder
+may need the public key in which case it should be checked to be trusted
+by the responder.
+
+The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_1 packet.
+It must not be sent in any other packet type. Following diagram
+represent the Key Exchange 1 Payload.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Public Key Length | Public Key Type |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Public Key of the Host (or certificate) ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Public Data Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Public Data (e = g ^ x mod p) ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2: Key Exchange 1 Payload
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the public key
+ (or certificate), including this field and public key type
+ field as well.
+
+o Public Key Type (2 bytes) - The public key (or certificate)
+ type. This field indicates the type of the public key in
+ the packet. Following types are defined:
+
+ 1 SILC style public key (mandatory)
+ 2 SSH2 style public key (optional)
+ 3 X.509 Version 3 certificate (optional)
+ 4 OpenPGP certificate (optional)
+ 5 SPKI certificate (optional)
+
+ The only required type to support is type number 1. See
+ [SILC1] for the SILC public key specification. See
+ SSH public key specification in [SSH-TRANS]. See X.509v3
+ certificate specification in [PKIX-Part1]. See OpenPGP
+ certificate specification in [PGP]. See SPKI certificate
+ specification in [SPKI]. If this field includes zero (0)
+ or unsupported type number the protocol must be aborted
+ sending SILC_PACKET_FAILURE message.
+
+o Public Data Length (2 bytes) - The length of the public
+ data computed by the responder, including this field
+ as well.
+
+o Public Data (variable length) - The public data to be
+ sent to the responder. See section 2.2 Key Exchange
+ Procedure for detailed description how this field is
+ computed. This value is binary encoded.
+.in 3
+
+
+.ti 0
+2.1.3 Key Exchange 2 Payload
+
+Key Exchange 2 Payload is used to deliver public key, computed public
+data and signature from responder to initiator. Initiator uses these
+public parts of the key exchange protocol to compute the shared secret.
+
+The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_2 packet.
+It must not be sent in any other packet type. Following diagram
+represent the Key Exchange 2 Payload.
+
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Public Key Length | Public Key Type |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Public Key of the Host (or certificate) ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Public Data Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Public Data (f = g ^ y mod p) ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Signature Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Signature Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3: Key Exchange 2 Payload
+
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the public key
+ (or certificate), including this field and public key type
+ field as well.
+
+o Public Key Type (2 bytes) - The public key (or certificate)
+ type. This field indicates the type of the public key in
+ the packet. See previous sections for defined public key
+ types.
+
+o Public Key of the host (variable length) - The public
+ key of the sender (or its certificate). This is verified
+ by the receiver of the packet. The type of this field
+ is indicated by previous Public Key Type field.
+
+o Public Data Length (2 bytes) - The length of the public
+ data computed by the responder, including this field
+ as well.
+
+o Public Data (variable length) - The public data computed
+ by the responder. See section 2.2 Key Exchange Procedure
+ for detailed description how this field is computed. This
+ value is binary encoded.
+
+o Signature Length (2 bytes) - The length of the signature,
+ including the length of this field as well.
+
+o Signature Data (variable length) - The signature signed
+ by the responder. The receiver of this signature must
+ verify it. The verification is done using the public
+ key received in this same payload. See section 2.2
+ Key Exchange Procedure for detailed description how
+ to produce the signature.
+
+
+.ti 0
+2.2 Key Exchange Procedure
+
+The key exchange begins by sending SILC_PACKET_KEY_EXCHANGE packet with
+Key Exchange Start Payload to select the security properties to be used
+in the key exchange and later in the communication.
+
+After Key Exchange Start Payload has been processed by both of the
+parties the protocol proceeds as follows:
+
+
+Setup: p is a large and public safe prime. This is one of the
+ Diffie Hellman groups. q is order of subgroup (largest
+ prime factor of p). g is a generator and is defined
+ along with the Diffie Hellman group.
+
+ 1. Initiator generates a random number x, where 1 < x < q,
+ and computes e = g ^ x mod p. The result e is then
+ encoded into Key Exchange 1 Payload and sent
+ to the responder.
+
+
+ 2. Responder generates a random number y, where 1 < y < q,
+ and computes f = g ^ y mod p. It then computes the
+ shared secret KEY = e ^ y mod p, and, a hash value
+ HASH = hash(Key Exchange Start Payload data | Host public
+ key (or certificate) | e | f | KEY). It then signs
+ the HASH value with its private key resulting a signature
+ SIGN.
+
+ It then encodes its public key (or certificate), f and
+ SIGN into Key Exchange 2 Payload and sends it to the
+ initiator.
+
+
+ 3. Initiator verifies that the public key provided in
+ the payload is authentic, or if certificates are used
+ it verifies the certificate. Initiator may accept
+ the public key without verifying it, however, doing
+ so may result to insecure key exchange (accepting the
+ public key without verifying may be desirable for
+ practical reasons on many environments. For long term
+ use this is never desirable, in which case certificates
+ would be the preferred method to use).
+
+ Initiator then computes the shared secret KEY =
+ f ^ x mod p, and, a hash value HASH in the same way as
+ responder did in phase 2. It then verifies the
+ signature SIGN from the payload with the hash value
+ HASH using the received public key.
+
+
+If any of these phases is to fail SILC_PACKET_FAILURE is sent to
+indicate that the key exchange protocol failed. Any other packets must
+not be sent or accepted during the key exchange except the
+SILC_PACKET_KEY_EXCHANGE_*, SILC_PACKET_DISCONNECT, SILC_PACKET_FAILURE
+and/or SILC_PACKET_SUCCESS packets.
+
+The result of this protocol is a shared secret key material KEY and
+a hash value HASH. The key material itself is not fit to be used as
+a key, it needs to be processed further to derive the actual keys to be
+used. The key material is also used to produce other security parameters
+later used in the communication. See section 2.3 Processing the Key
+Material for detailed description how to process the key material.
+
+After the keys are processed the protocol is ended by sending the
+SILC_PACKET_SUCCESS packet. Both entities send this packet to
+each other. After this both parties will start using the new keys.
+
+
+
+.ti 0
+2.3 Processing the Key Material
+
+Key Exchange protocol produces secret shared key material KEY. This
+key material is used to derive the actual keys used in the encryption
+of the communication channel. The key material is also used to derive
+other security parameters used in the communication. Key Exchange
+protocol produces a hash value HASH as well. This is used in the key
+deriving process as a session identifier.
+
+Keys are derived from the key material as follows:
+
+.in 6
+Sending Initial Vector (IV) = hash(0 | KEY | HASH)
+Receiving Initial Vector (IV) = hash(1 | KEY | HASH)
+Sending Encryption Key = hash(2 | KEY | HASH)
+Receiving Encryption Key = hash(3 | KEY | HASH)
+HMAC Key = hash(4 | KEY | HASH)
+.in 3
+
+
+The Initial Vector (IV) is used in the encryption when doing for
+example CBC mode. As many bytes as needed are taken from the start of
+the hash output for IV. Sending IV is for sending key and receiving IV
+is for receiving key. For receiving party, the receiving IV is actually
+sender's sending IV, and, the sending IV is actually sender's receiving
+IV. Initiator uses IV's as they are (sending IV for sending and
+receiving IV for receiving).
+
+The Encryption Keys are derived as well from the hash(). If the hash()
+output is too short for the encryption algorithm more key material is
+produced in following manner:
+
+.in 6
+K1 = hash(2 | KEY | HASH)
+K2 = hash(KEY | K1)
+K3 = hash(KEY | K1 | K2) ...
+
+Sending Encryption Key = K1 | K2 | K3 ...
+
+
+K1 = hash(3 | KEY | HASH)
+K2 = hash(KEY | K1)
+K3 = hash(KEY | K1 | K2) ...
+
+Receiving Encryption Key = K1 | K2 | K3 ...
+.in 3
+
+
+The key is distributed by hashing the previous hash with the original
+key material. The final key is a concatenation of the hash values.
+For Receiving Encryption Key the procedure is equivalent. Sending key
+is used only for encrypting data to be sent. The receiving key is used
+only to decrypt received data. For receiving party, the receive key is
+actually sender's sending key, and, the sending key is actually sender's
+receiving key. Initiator uses generated keys as they are (sending key
+for sending and receiving key for sending).
+
+The HMAC key is used to create MAC values to packets in the communication
+channel. As many bytes as needed are taken from the start of the hash
+output.
+
+These procedures are performed by all parties of the key exchange
+protocol. This must be done before the protocol has been ended by
+sending the SILC_PACKET_SUCCESS packet.
+
+
+.ti 0
+2.4 SILC Key Exchange Groups
+
+Following groups may be used in the SILC Key Exchange protocol. The
+first group diffie-hellman-group1 is mandatory, other groups maybe
+negotiated to be used in the connection with Key Exchange Start Payload
+and SILC_PACKET_KEY_EXCHANGE packet. However, the first group must be
+proposed in the Key Exchange Start Payload regardless of any other
+requested group (however, it doesn't have to be the first on the list).
+
+
+.ti 0
+2.4.1 diffie-hellman-group1
+
+The length of this group is 1024 bits. This is mandatory group.
+The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
+
+Its decimal value is
+
+.in 6
+179769313486231590770839156793787453197860296048756011706444
+423684197180216158519368947833795864925541502180565485980503
+646440548199239100050792877003355816639229553136239076508735
+759914822574862575007425302077447712589550957937778424442426
+617334727629299387668709205606050270810842907692932019128194
+467627007
+.in 3
+
+Its hexadecimal value is
+
+.in 6
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
+FFFFFFFF FFFFFFFF
+.in 3
+
+
+The generator used with this prime is g = 2. The group order q is
+(p - 1) / 2.
+
+This group was taken from the OAKLEY specification.
+
+
+.ti 0
+2.4.2 diffie-hellman-group2
+
+The length of this group is 1536 bits. This is optional group.
+The prime is 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }.
+
+Its decimal value is
+
+.in 6
+241031242692103258855207602219756607485695054850245994265411
+694195810883168261222889009385826134161467322714147790401219
+650364895705058263194273070680500922306273474534107340669624
+601458936165977404102716924945320037872943417032584377865919
+814376319377685986952408894019557734611984354530154704374720
+774996976375008430892633929555996888245787241299381012913029
+459299994792636526405928464720973038494721168143446471443848
+8520940127459844288859336526896320919633919
+.in 3
+
+Its hexadecimal value is
+
+.in 6
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
+.in 3
+
+The generator used with this prime is g = 2. The group order q is
+(p - 1) / 2.
+
+This group was taken from the OAKLEY specification.
+
+
+.ti 0
+2.5 Key Exchange Status Types
+
+This section defines all key exchange protocol status types that may be
+returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets to
+indicate the status of the protocol. Implementations may map the
+status types to human readable error message. All types except the
+SILC_SKE_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
+Following status types are defined:
+
+.in 6
+0 SILC_SKE_STATUS_OK
+
+ Protocol were exeucted succesfully.
+
+
+1 SILC_SKE_STATUS_ERROR
+
+ Unknown error occured. No specific error type is defined.
+
+
+2 SILC_SKE_STATUS_BAD_PAYLOAD
+
+ Provided KE payload were malformed or included bad fields.
+
+
+3 SILC_SKE_STATUS_UNSUPPORTED_GROUP
+
+ None of the provided groups were supported.
+
+
+4 SILC_SKE_STATUS_UNSUPPORTED_CIPHER
+
+ None of the provided ciphers were supported.
+
+
+5 SILC_SKE_STATUS_UNSUPPORTED_PKCS
+
+ None of the provided public key algorithms were supported.
+
+
+6 SILC_SKE_STATUS_UNSUPPORTED_HASH_FUNCTION
+
+ None of the provided hash functions were supported.
+
+
+7 SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY
+
+ Provided public key type is not supported.
+
+
+8 SILC_SKE_STATUS_INCORRECT_SIGNATURE
+
+ Provided signature was incorrect.
+.in 3
+
+
+
+
+
+.ti 0
+3 SILC Connection Authentication Protocol
+
+Purpose of Connection Authentication protocol is to authenticate the
+connecting party with server. Usually connecting party is client but
+server may connect to server as well. Its other purpose is to provide
+information for the server about which type of connection this is.
+The type defines whether this is client, server or router connection.
+Server uses this information to create the ID for the connection. After
+the authentication protocol has been successfully completed
+SILC_PACKET_NEW_ID must be sent to the connecting party by the server.
+See section New ID Payload in [SILC2] for detailed description for this
+packet's payload.
+
+Server must verify the authentication data received and if it is to fail
+the authentication must be failed by sending SILC_PACKET_FAILURE packet.
+If everything checks out fine the protocol is ended by server by sending
+SILC_PACKET_SUCCESS packet.
+
+The protocol is executed after the SILC Key Exchange protocol. It must
+not be executed in any other time. As it is performed after key exchange
+protocol all traffic in the connection authentication protocol is
+encrypted with the exchanged keys.
+
+The protocol is started by the connecting party by sending
+SILC_PACKET_CONNECTION_AUTH packet with Connection Auth Payload,
+described in the next section. This payload must include the
+authentication data. Authentication data is set according
+authentication method that must be known by both parties. If connecting
+party does not know what is the mandatory authentication method it must
+request it from the server by sending SILC_PACKET_CONNECTION_AUTH_REQUEST
+packet. This packet is not part of this protocol and is described in
+section Connection Auth Request Payload in [SILC2]. However, if
+connecting party already knows the mandatory authentication method
+sending the request is not necessary.
+
+See [SILC1] and section Connection Auth Request Payload in [SILC2] also
+for the list of different authentication methods. Authentication method
+may also be NONE, in which case the server does not require
+authentication at all. However, in this case the protocol still must be
+executed; the authentication data just is empty indicating no
+authentication is required.
+
+If authentication method is passphrase the authentication data is
+plaintext passphrase. As the payload is entirely encrypted it is safe
+to have plaintext passphrase. 3.2.1 Passphrase Authentication for
+more information.
+
+
+If authentication method is public key authentication the authentication
+data is signature of the hash value HASH plus Key Exchange Start Payload,
+established by the SILC Key Exchange protocol. This signature must then
+be verified by the server. See section 3.2.2 Public Key Authentication
+for more information.
+
+The connecting party of this protocol must wait after successful execution
+of this protocol for the SILC_PACKET_NEW_ID packet where it will receive
+the ID it will be using in the SILC network. Connecting party cannot
+start normal SILC session (sending messages or commands) until it has
+received its ID. The ID's are always created by the server except
+for server to server connection where servers create their own ID's.
+
+
+
+.ti 0
+3.1 Connection Auth Payload
+
+Client sends this payload to authenticate itself to the server. Server
+connecting to another server also sends this payload. Server receiving
+this payload must verify all the data in it and if something is to fail
+the authentication must be failed by sending SILC_PACKET_FAILURE packet.
+
+The payload may only be sent with SILC_PACKET_CONNECTION_AUTH packet.
+It must not be sent in any other packet type. Following diagram
+represent the Connection Auth Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Payload Length | Connection Type |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Authentication Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 4: Connection Auth Payload
+
+
+.in 6
+o Payload Length (2 bytes) - Length of the entire Connection
+ Auth Payload.
+
+o Connection Type (2 bytes) - Indicates the type of the
+ connection. See section Connection Auth Request Payload
+ in [SILC2] for the list of connection types. This field must
+ include valid connection type or the packet must be discarded
+ and authentication must be failed.
+
+o Authentication Data (variable length) - The actual
+ authentication data. Contents of this depends on the
+ authentication method known by both parties. If no
+ authentication is required this field does not exist.
+.in 3
+
+
+.ti 0
+3.2 Connection Authentication Types
+
+SILC supports two authentication types to be used in the connection
+authentication protocol; passphrase or public key based authentication.
+Following sections defines the authentication methods. See [SILC2]
+for defined numerical authentication method types.
+
+
+.ti 0
+3.2.1 Passphrase Authentication
+
+Passphrase authentication or pre-shared-key base authentication is
+simply an authentication where the party that wants to authenticate
+itself to the other end sends the passphrase that is required by
+the other end, for example server.
+
+If the passphrase matches with the one in the server's end the
+authentication is successful. Otherwise SILC_PACKET_FAILURE must be
+sent to the sender and the protocol execution fails.
+
+This is required authentication method to be supported by all SILC
+implementations.
+
+
+.ti 0
+3.2.2 Public Key Authentication
+
+Public key authentication may be used if passphrase based authentication
+is not desired. The public key authentication works by sending a
+signature as authentication data to the other end, say, server. The
+server must then verify the signature by the public key of the sender,
+which the server has received earlier in SKE protocol.
+
+The signature is computed using the private key of the sender by signing
+the HASH value provided by the SKE protocol previously, and the Key
+Exchange Start Payload from SKE protocol that was sent to the server.
+The server must verify the data, thus it must keep the HASH and the
+Key Exchange Start Payload saved during SKE and authentication protocols.
+
+If the verified signature matches the sent signature, the authentication
+were successful and SILC_PACKET_SUCCESS is sent. If it failed the protocol
+execution is stopped and SILC_PACKET_FAILURE is sent.
+
+This is required authentication method to be supported by all SILC
+implementations.
+
+
+.ti 0
+3.3 Connection Authentication Status Types
+
+This section defines all connection authentication status types that
+may be returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets
+to indicate the status of the protocol. Implementations may map the
+status types to human readable error message. All types except the
+SILC_AUTH_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
+Following status types are defined:
+
+0 SILC_AUTH_OK
+
+ Protocol was executed succesfully.
+
+
+1 SILC_AUTH_FAILED
+
+ Authentication failed.
+
+
+.ti 0
+4 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+5 References
+
+[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
+ Protocol Specification", Internet Draft, June 2000.
+
+[SILC2] Riikonen, P., "SILC Packet Protocol", Internet Draft,
+ June 2000.
+
+[IRC] Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+ RFC 1459, May 1993.
+
+[SSH-TRANS] Ylonen, T., et al, "SSH Transport Layer Protocol",
+ Internet Draft.
+
+[PGP] Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+ November 1998.
+
+[SPKI] Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+ September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+ Infrastructure, Certificate and CRL Profile", RFC 2459,
+ January 1999.
+
+[Schneier] Schneier, B., "Applied Cryptography Second Edition",
+ John Wiley & Sons, New York, NY, 1996.
+
+[Menezes] Menezes, A., et al, "Handbook of Applied Cryptography",
+ CRC Press 1997.
+
+[OAKLEY] Orman, H., "The OAKLEY Key Determination Protocol",
+ RFC 2412, November 1998.
+
+[ISAKMP] Maughan D., et al, "Internet Security Association and
+ Key Management Protocol (ISAKMP)", RFC 2408, November
+ 1998.
+
+[IKE] Harkins D., and Carrel D., "The Internet Key Exhange
+ (IKE)", RFC 2409, November 1998.
+
+[HMAC] Krawczyk, H., "HMAC: Keyed-Hashing for Message
+ Authentication", RFC 2104, February 1997.
+
+
+.ti 0
+6 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
--- /dev/null
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 27 June 2000
+.ds CH SILC Packet Protocol
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group P. Riikonen
+Internet-Draft
+draft-riikonen-silc-pp-00.txt 27 June 2000
+Expires: 27 Jan 2001
+
+.in 3
+
+.ce
+SILC Packet Protocol
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other
+documents at any time. It is inappropriate to use Internet-Drafts
+as reference material or to cite them other than as
+``work in progress.''
+
+To learn the current status of any Internet-Draft, please check the
+``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes a Packet Protocol used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification Internet Draft [SILC1]. This
+protocol describes the packet types and packet payloads which defines
+the contents of the packets. The protocol provides secure binary packet
+protocol that assures that the contents of the packets are secured and
+authenticated.
+
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction .................................................. 3
+2 SILC Packet Protocol .......................................... 4
+ 2.1 SILC Packet ............................................... 4
+ 2.2 SILC Packet Header ........................................ 5
+ 2.3 SILC Packet Types ......................................... 7
+ 2.3.1 SILC Packet Payloads ................................ 15
+ 2.3.2 Disconnect Payload .................................. 15
+ 2.3.3 Success Payload ..................................... 16
+ 2.3.4 Failure Payload ..................................... 16
+ 2.3.5 Reject Payload ...................................... 17
+ 2.3.6 Notify Payload ...................................... 17
+ 2.3.7 Error Payload ....................................... 18
+ 2.3.8 Channel Message Payload ............................. 19
+ 2.3.9 Channel Key Payload ................................. 20
+ 2.3.10 Private Message Payload ............................ 23
+ 2.3.11 Private Message Key Payload ........................ 24
+ 2.3.12 Command Payload .................................... 25
+ 2.3.12.1 Command Argument Payload .................. 25
+ 2.3.13 Command Reply Payload .............................. 26
+ 2.3.14 Connection Auth Request Payload .................... 27
+ 2.3.15 New ID Payload ..................................... 28
+ 2.3.16 New ID List Payload ................................ 29
+ 2.3.17 New Client Payload ................................. 29
+ 2.3.18 New Server Payload ................................. 31
+ 2.3.19 New Channel Payload ................................ 31
+ 2.3.20 New Channel User Payload ........................... 32
+ 2.3.21 New Channel List Payload ........................... 33
+ 2.3.22 New Channel User List Payload ...................... 34
+ 2.3.23 Replace ID Payload ................................. 34
+ 2.3.24 Remove ID Payload .................................. 35
+ 2.4 SILC ID Types ............................................. 36
+ 2.5 Packet Encryption And Decryption .......................... 37
+ 2.5.1 Normal Packet Encryption And Decryption ............. 37
+ 2.5.2 Channel Message Encryption And Decryption ........... 37
+ 2.5.3 Private Message Encryption And Decryption ........... 38
+ 2.6 Packet MAC Generation ..................................... 39
+ 2.7 Packet Padding Generation ................................. 39
+ 2.8 Packet Compression ........................................ 40
+ 2.9 Packet Sending ............................................ 40
+ 2.10 Packet Reception ......................................... 41
+ 2.11 Packet Broadcasting ...................................... 41
+ 2.12 Packet Routing ........................................... 42
+ 2.13 Packet Tunneling ......................................... 42
+3 Security Considerations ....................................... 43
+4 References .................................................... 43
+5 Author's Address .............................................. 44
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1: Typical SILC Packet
+Figure 2: SILC Packet Header
+Figure 3: Disconnect Payload
+Figure 4: Success Payload
+Figure 5: Failure Payload
+Figure 6: Reject Payload
+Figure 7: Notify Payload
+Figure 8: Error Payload
+Figure 9: Channel Message Payload
+Figure 10: Channel Key Payload
+Figure 11: Private Message Payload
+Figure 12: Private Message Key Payload
+Figure 13: Command Payload
+Figure 14: Command Argument Payload
+Figure 15: Connection Auth Request Payload
+Figure 16: New ID Payload
+Figure 17: New Client Payload
+Figure 18: New Server Payload
+Figure 19: New Channel Payload
+Figure 20: New Channel User Payload
+Figure 21: Replace ID Payload
+Figure 22: Remove ID Payload
+
+
+.ti 0
+1. Introduction
+
+This document describes a Packet Protocol used in the Secure Internet
+Live Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification Internet Draft [SILC1]. This
+protocol describes the packet types and packet payloads which defines
+the contents of the packets. The protocol provides secure binary packet
+protocol that assures that the contents of the packets are secured and
+authenticated.
+
+The basis of SILC protocol relies in the SILC packets and it is with
+out a doubt the most important part of the protocol. It is also probably
+the most complicated part of the protocol. Packets are used all the
+time in the SILC network to send messages, commands and other information.
+All packets in SILC network are always encrypted and their integrity
+is assured by computed MACs. The protocol defines several packet types
+and packet payloads. Each packet type usually has a specific packet
+payload that actually defines the contents of the packet. Each packet
+also includes a default SILC Packet Header that provides sufficient
+information about the origin of the packet and destination of the
+packet.
+
+
+.ti 0
+2 SILC Packet Protocol
+
+.ti 0
+2.1 SILC Packet
+
+SILC packets deliver messages from sender to receiver securely by
+encrypting important fields of the packet. The packet consists of
+default SILC Packet Header, Padding, Packet Payload data, and, packet
+MAC.
+
+The following diagram illustrates typical SILC packet.
+
+
+.in 5
+.nf
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+| n bytes | 1 - n bytes | n bytes | n bytes
+| SILC Header | Padding | Data Payload | MAC
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.in 3
+
+.ce
+Figure 1: Typical SILC Packet
+
+
+SILC Header is always the first part of the packet and its purpose
+is to provide information about the packet. It provides for example
+the packet type, origin of the packet and the destination of the packet.
+The header is variable in length and first two (2) bytes of the
+header (thus first two bytes of the packet) are not encrypted. The
+first two (2) bytes are the length of the packet which is not encrypted.
+See following section for description of SILC Packet header. Packets
+without SILC header or with malformed SILC header must be dropped.
+
+Padding follows the packet header. The purpose of the padding is to
+make the packet multiple by eight (8) or by the block size of the
+cipher used in the encryption, which ever is larger. The maximum
+length of padding is currently 16 bytes. The padding is always
+encrypted.
+
+Data payload area follows padding and it is the actual data of the
+packet. The packet data is the packet payloads defined in this
+protocol. The data payload area is always encrypted.
+
+The last part of SILC packet is the packet MAC that assures the
+integrity of the packet. The MAC is always computed from the packet
+before the encryption is applied to the packet. If compression is used
+in the packet the MAC is computed after the compression has been
+applied. The compression, on the other hand, is always applied before
+encryption.
+
+All fields in all packet payloads are always in MSB (most significant
+byte first) order.
+
+
+.ti 0
+2.2 SILC Packet Header
+
+The default SILC packet header is applied to all SILC packets and it is
+variable in length. The purpose of SILC Packet header is to provide
+detailed information about the packet. The receiver of the packet uses
+the packet header to parse the packet and gain other relevant parameters
+of the packet.
+
+Following diagram represents the default SILC header format.
+(*) indicates that this field is never encrypted. Other fields are
+always encrypted.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Payload Length * | Flags | Packet Type |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Source ID Length | Destination ID Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Src ID Type | |
++-+-+-+-+-+-+-+-+ +
+| |
+~ Source ID ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Dst ID Type | |
++-+-+-+-+-+-+-+-+ +
+| |
+~ Destination ID ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2: SILC Packet Header
+
+
+.in 6
+o Payload Length (2 bytes) - Is the length of the packet
+ not including the padding of the packet. This field must
+ not be encrypted but must always be authenticated.
+
+o Flags (1 byte) - Indicates flags to be used in packet
+ processing. Several flags may be set by ORing the flags
+ together.
+
+ Following flags are reserved for this field:
+
+
+
+
+ No flags 0x00
+
+ In this case the field is ignored.
+
+
+ Private Message Key 0x01
+
+ Indicates that the packet must include private
+ message that is encrypted using private key set by
+ client. Servers does not know anything about this
+ key and this causes that the private message is
+ not handled by the server at all, it is just
+ passed along. See section 2.5.3 Private Message
+ Encryption And Decryption for more information.
+
+
+ Broadcast 0x02
+
+ Marks the packet to be broadcasted. Client cannot
+ send broadcast packet and normal server cannot send
+ broadcast packet. Only router server may send broadcast
+ packet. The router receiving of packet with this flag
+ set must send (broadcast) the packet to its primary
+ route. If router has several router connections the
+ packet may be sent only to the primary route. See
+ section 2.11 Packet Broadcasting for description of
+ packet broadcasting.
+
+
+ Tunneled 0x04
+
+ Marks that the packet is tunneled. Tunneling means
+ that extra SILC Packet Header has been applied to the
+ original packet. The outer header has this flag
+ set. See section 2.13 Packet Tunneling for more
+ information.
+.in 3
+
+
+
+o Packet Type (1 byte) - Is the type of the packet. Receiver
+ uses this field to parse the packet. See section 2.3
+ SILC Packets for list of defined packet types.
+
+o Source ID Length (2 bytes) - Indicates the length of the
+ Source ID field in the header, not including this or any
+ other fields.
+
+
+
+o Destination ID Length (2 bytes) - Indicates the length of the
+ Destination ID field in the header, not including this or
+ any other fields.
+
+o Src ID Type (1 byte) - Indicates the type of ID in the
+ Source ID field. See section 2.4 SILC ID Types for
+ defined ID types.
+
+o Source ID (variable length) - The actual source ID that
+ indicates who is the original sender of the packet.
+
+o Dst ID Type (1 byte) - Indicates the type of ID in the
+ Destination ID field. See section 2.4 SILC ID Types for
+ defined ID types.
+
+o Destination ID (variable length) - The actual source ID that
+ indicates who is the end receiver of the packet.
+
+
+.ti 0
+2.3 SILC Packet Types
+
+SILC packet types defines the contents of the packet and it is used by
+the receiver to parse the packet. The packet type is 8 bits, as a one
+byte, in length. The range for the packet types are from 0 - 255,
+where 0 is never sent and 255 is currently reserved for future
+extensions and must not be defined to any other purpose. Every SILC
+specification compliant implementation should support all of these packet
+types.
+
+The below list of the SILC Packet types includes reference to the packet
+payload as well. Packet payloads are the actual packet, that is, the data
+that the packet consists of. Each packet type defines packet payload
+which usually may only be sent with the specific packet type.
+
+Most of the packets are packets that must be destined directly to entity
+that is connected to the sender. It is not allowed, for example, for
+router to send disconnect packet to client that is not directly connected
+to the router. However, there are some special packet types that may
+be destined to some entity that the sender has not direct connection
+with. These packets are for example private message packets, channel
+message packets, command packets and some other packets that may be
+broadcasted in the SILC network. If the packet is allowed to be sent to
+indirectly connected entity it is mentioned separately in the packet
+description (unless it is obvious as in private and channel message
+packets). Other packets must not be sent or accepted, if sent, to
+indirectly connected entities.
+
+List of SILC Packet types are defined as follows.
+
+.in 1
+ 0 SILC_PACKET_NONE
+
+ This type is reserved and it is never sent.
+
+
+ 1 SILC_PACKET_DISCONNECT
+
+ This packet is sent to disconnect the remote end. Reason of
+ the disconnection is sent inside the packet payload. Client
+ usually does not send this packet.
+
+ Payload of the packet: See section 2.3.2 Disconnect Payload
+
+
+ 2 SILC_PACKET_SUCCESS
+
+ This packet is sent upon successful execution of some protocol.
+ The status of the success is sent in the packet.
+
+ Payload of the packet: See section 2.3.3 Success Payload
+
+
+ 3 SILC_PACKET_FAILURE
+
+ This packet is sent upon failure of some protocol. The status
+ of the failure is sent in the packet.
+
+ Payload of the packet: See section 2.3.4 Failure Payload
+
+
+ 4 SILC_PACKET_REJECT
+
+ This packet may be sent upon rejection of some protocol.
+ The status of the rejection is sent in the packet.
+
+ Payload of the packet: See section 2.3.5 Reject Payload
+
+
+ 5 SILC_PACKET_NOTIFY
+
+ This packet is used to send notify message, usually from
+ server to client, although it may be sent from server to another
+ server as well. Client never sends this packet. Server may
+ send this packet to channel as well when the packet is
+ distributed to all clients on the channel. Receiver of this
+ packet may ignore the packet if it chooses so. However, it
+ should not be ignored.
+
+ Payload of the packet: See section 2.3.6 Notify Payload.
+
+
+ 6 SILC_PACKET_ERROR
+
+ This packet is sent when an error occurs. Server may
+ send this packet. Client never sends this packet. The
+ client may entirely ignore the packet, however, server is
+ most likely to take action anyway.
+
+ Payload of the packet: See section 2.3.7 Error Payload.
+
+
+ 7 SILC_PACKET_CHANNEL_MESSAGE
+
+ This packet is used to send messages to channels. The packet
+ includes Channel ID of the channel and the actual message to
+ the channel. Messages sent to the channel are always protected
+ by channel specific keys. Channel Keys are distributed by
+ SILC_PACKET_CHANNEL_KEY packet.
+
+ When client sends this packet the destination ID in the SILC
+ header must be the Channel ID of the channel the message is
+ destined to. If server sends this packet to a client the
+ destination ID in the SILC header must be the Client ID of
+ the client receiving the packet.
+
+ If server sends this packet to router or if router sends this
+ packet to server or another router the destination ID in the
+ SILC header must be the Channel ID of the channel. Server
+ (including router) distributes this packet only to its local
+ clients who are joined to the channel. Servers and routers
+ also determines who are on the channel and when this packet
+ needs to be sent, as described in section Client To Client
+ in [SILC1].
+
+ Payload of the packet: See section 2.3.8 Channel Message
+ Payload
+
+
+ 8 SILC_PACKET_CHANNEL_KEY
+
+ This packet is used to distribute new key for particular
+ channel. Each channel has their own independent keys that
+ is used to protect the traffic on the channel. Only server
+ may send this packet. This packet may be sent to entity
+ that is indirectly connected to the sender.
+
+ Payload of the packet: See section 2.3.9 Channel Key Payload
+
+
+ 9 SILC_PACKET_PRIVATE_MESSAGE
+
+ This packet is used to send private messages from client
+ to another client. By default, private messages are protected
+ by session keys established by normal key exchange protocol.
+ However, it is possible to use specific key to protect private
+ messages. SILC_PACKET_PRIVATE_MESSAGE_KEY packet is used to
+ agree the key with the remote client. Pre-shared key may be
+ used as well if both of the client knows it, however, it needs
+ to be agreed outside SILC. See more of this in [SILC1].
+
+ Payload of the packet: See section 2.3.10 Private Message
+ Payload
+
+
+ 10 SILC_PACKET_PRIVATE_MESSAGE_KEY
+
+ This packet is used to agree about a key to be used to protect
+ the private messages between two clients. If this is not sent
+ the normal session key is used to protect the private messages
+ inside SILC network. Agreeing to use specific key to protect
+ private messages adds security, as no server between the two
+ clients will be able to decrypt the private message. However,
+ servers inside SILC network are considered to be trusted, thus
+ using normal session key to protect private messages does not
+ degree security. Whether to agree to use specific keys by
+ default or to use normal session keys by default, is
+ implementation specific issue. See more of this in [SILC1].
+
+ Payload of the packet: See section 2.3.11 Private Message
+ Key Payload
+
+
+ 11 SILC_PACKET_COMMAND
+
+ This packet is used to send commands from client to server.
+ Server may send this packet to other servers as well. All
+ commands are listed in their own section SILC Command Types
+ in [SILC1]. The contents of this packet is command specific.
+ This packet may be sent to entity that is indirectly connected
+ to the sender.
+
+ Payload of the packet: See section 2.3.12 Command Payload
+
+
+ 12 SILC_PACKET_COMMAND_REPLY
+
+ This packet is send as reply to the SILC_PACKET_COMMAND packet.
+ The contents of this packet is command specific. This packet
+ maybe sent to entity that is indirectly connected to the sender.
+
+ Payload of the packet: See section 2.3.13 Command Reply
+ Payload and section 2.3.12 Command
+ Payload
+
+
+ 13 SILC_PACKET_KEY_EXCHANGE
+
+ This packet is used to start SILC Key Exchange Protocol,
+ described in detail in [SILC3].
+
+ Payload of the packet: Payload of this packet is described
+ in the section SILC Key Exchange
+ Protocol and its sub sections in
+ [SILC3].
+
+
+ 14 SILC_PACKET_KEY_EXCHANGE_1
+
+ This packet is used as part of the SILC Key Exchange Protocol.
+
+ Payload of the packet: Payload of this packet is described
+ in the section SILC Key Exchange
+ Protocol and its sub sections in
+ [SILC3].
+
+
+ 15 SILC_PACKET_KEY_EXCHANGE_2
+
+ This packet is used as part of the SILC Key Exchange Protocol.
+
+ Payload of the packet: Payload of this packet is described
+ in the section SILC Key Exchange
+ Protocol and its sub sections in
+ [SILC3].
+
+
+ 16 SILC_PACKET_CONNECTION_AUTH_REQUEST
+
+ This packet is used to request the authentication method to
+ be used in the SILC Connection Authentication Protocol. If
+ initiator of the protocol does not know the mandatory
+ authentication method this packet is used to determine it.
+
+ The party receiving this payload must respond with the same
+ packet including the mandatory authentication method.
+
+ Payload of the packet: See section 2.3.14 Connection Auth
+ Request Payload
+
+
+ 17 SILC_PACKET_CONNECTION_AUTH
+
+ This packet is used to start and perform the SILC Connection
+ Authentication Protocol. This protocol is used to authenticate
+ the connecting party. The protocol is described in detail in
+ [SILC3].
+
+ Payload of the packet: Payload of this packet is described
+ in the section SILC Authentication
+ Protocol and it sub sections in [SILC].
+
+
+ 18 SILC_PACKET_NEW_ID
+
+ This packet is used to distribute new ID's from server to
+ router and from router to all routers in the SILC network.
+ This is used when for example new client is registered to
+ SILC network. The newly created ID's of these operations are
+ distributed by this packet. Only server may send this packet,
+ however, client must be able to receive this packet.
+
+ Payload of the packet: See section 2.3.15 New ID Payload
+
+
+ 19 SILC_PACKET_NEW_ID_LIST
+
+ This packet is used to distribute list of new ID's from
+ server to routers. This is equivalent to previous packet
+ type except that it may include several ID's. Client must
+ not send this packet.
+
+ Payload of the packet: See section 2.3.16 New ID List
+ Payload
+
+
+ 20 SILC_PACKET_NEW_CLIENT
+
+ This packet is used by client to register itself to the
+ SILC network. This is sent after key exchange and
+ authentication protocols has been completed. Client sends
+ various information about itself in this packet.
+
+ Payload of the packet: See section 2.3.17 New Client Payload
+
+
+ 21 SILC_PACKET_NEW_SERVER
+
+ This packet is used by server to register itself to the
+ SILC network. This is sent after key exchange and
+ authentication protocols has been completed. Server sends
+ this to the router it connected to, or, if router was
+ connecting, to the connected router. Server sends
+ its Server ID and other information in this packet.
+ Client must not send or receive this packet.
+
+ Payload of the packet: See section 2.3.18 New Server Payload
+
+
+ 22 SILC_PACKET_NEW_CHANNEL
+
+ This packet is used to notify routers about newly created
+ channel. Channels are always created by the router and it must
+ notify other routers about the created channel. Router sends
+ this packet to its primary route. Client must not send this
+ packet. This packet maybe sent to entity that is indirectly
+ connected to the sender.
+
+ Payload of the packet: See section 2.3.19 New Channel Payload
+
+
+ 23 SILC_PACKET_NEW_CHANNEL_USER
+
+ This packet is used to notify routers about new user on channel.
+ The packet is sent after user has joined to the channel. Server
+ may send this packet to its router and router may send this to
+ its primary router. Client must not send this packet. This
+ packet maybe sent to entity that is indirectly connected to the
+ sender.
+
+ Payload of the packet: See section 2.3.20 New Channel User
+ Payload
+
+
+ 24 SILC_PACKET_NEW_CHANNEL_LIST
+
+ This packet is used to distribute list of created channels
+ from server to routers. This is equivalent to the packet
+ SILC_PACKET_NEW_CHANNEL except that it may include several
+ payloads. Client must not send this packet.
+
+ Payload of the packet: See section 2.3.21 New Channel List
+ Payload
+
+
+ 25 SILC_PACKET_NEW_CHANNEL_USER_LIST
+
+ This packet is used to distribute list of users on specific
+ channel from server to routers. This is equivalent to the
+ packet SILC_PACKET_NEW_CHANNEL_USER except that it may
+ include several payloads. Client must not send this packet.
+
+ Payload of the packet: See section 2.3.22 New Channel User
+ List Payload
+
+
+ 26 SILC_PACKET_REPLACE_ID
+
+ This packet is used to replace old ID with new ID sent in
+ the packet payload. For example, when client changes its
+ nickname new ID is created and this packet can be used to
+ distribute the new ID and the old ID is removed when it is
+ send in the packet. Client cannot send or receive this
+ packet. This packet maybe sent to entity that is indirectly
+ connected to the sender.
+
+ Payload of the packet: See section 2.3.23 Replace ID Payload
+
+
+ 27 SILC_PACKET_REMOVE_ID
+
+ This packet is used to removed ID. For example, when client
+ exits SILC network its ID is removed. Client must not send
+ this packet. This packet maybe sent to entity that is
+ indirectly connected to the sender.
+
+ Payload of the packet: See section 2.3.24 Remove ID Payload
+
+
+ 28 SILC_PACKET_REKEY
+
+ This packet is used to indicate that re-key must be performed
+ for session keys. See section Session Key Regeneration in
+ [SILC1] for more information. This packet does not have
+ a payload.
+
+
+
+
+ 29 SILC_PACKET_REKEY_DONE
+
+ This packet is used to indicate that re-key is performed and
+ new keys must be used hereafter. This is sent only if re-key
+ was done without PFS option. If PFS is set, this is not sent
+ as SILC Key Exchange protocol is executed. This packet does
+ not have a payload.
+
+
+ 30 - 254
+
+ Currently undefined commands.
+
+
+ 255 SILC_PACKET_MAX
+
+ This type is reserved for future extensions and currently it
+ is not sent.
+.in 3
+
+
+.ti 0
+2.3.1 SILC Packet Payloads
+
+All payloads resides in the main data area of the SILC packet. However
+all payloads must be at the start of the data area after the default
+SILC packet header and padding. All fields in the packet payload are
+always encrypted, as, they reside in the data area of the packet which
+is always encrypted.
+
+Payloads described in this section are common payloads that must be
+accepted anytime during SILC session. Most of the payloads may only
+be sent with specific packet type which is defined in the description
+of the payload.
+
+There are a lot of other payloads in the SILC as well. However, they
+are not common in the sense that they could be sent at any time.
+These payloads are not described in this section. These are payloads
+such as SILC Key Exchange payloads and so on. These are described
+in [SILC1] and [SILC3].
+
+
+.ti 0
+2.3.2 Disconnect Payload
+
+Disconnect payload is sent upon disconnection. The payload is simple;
+reason of disconnection is sent to the disconnected party.
+
+The payload may only be sent with SILC_PACKET_DISCONNECT packet. It
+must not be sent in any other packet type. Following diagram represents
+the Disconnect Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Disconnect Message ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3: Disconnect Payload
+
+
+
+
+.in 6
+o Disconnect Message (variable length) - Human readable
+ reason of the disconnection.
+.in 3
+
+
+.ti 0
+2.3.3 Success Payload
+
+Success payload is sent when some protocol execution is successfully
+completed. The payload is simple; indication of the success is sent.
+This maybe any data, including binary or human readable data.
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Success Indication ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 4: Success Payload
+
+
+.in 6
+o Success Indication (variable length) - Indication of
+ the success. This maybe for example some flag that
+ indicates the protocol and the success status or human
+ readable success message. The true length of this
+ payload is available by calculating it from the SILC
+ Packet Header.
+.in 3
+
+
+.ti 0
+2.3.4 Failure Payload
+
+This is opposite of Success Payload. Indication of failure of
+some protocol is sent in the payload.
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Failure Indication ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5: Failure Payload
+
+
+.in 6
+o Failure Indication (variable length) - Indication of
+ the failure. This maybe for example some flag that
+ indicates the protocol and the failure status or human
+ readable failure message. The true length of this
+ payload is available by calculating it from the SILC
+ Packet Header.
+.in 3
+
+
+.ti 0
+2.3.5 Reject Payload
+
+This payload is sent when some protocol is rejected to be executed.
+Other operations may send this as well that was rejected. The
+indication of the rejection is sent in the payload. The indication
+may be binary or human readable data.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Reject Indication ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6: Reject Payload
+
+
+.in 6
+o Reject Indication (variable length) - Indication of
+ the rejection. This maybe for example some flag that
+ indicates the protocol and the rejection status or human
+ readable rejection message. The true length of this
+ payload is available by calculating it from the SILC
+ Packet Header.
+.in 3
+
+
+.ti 0
+2.3.6 Notify Payload
+
+Notify payload is used to send notify messages. The payload is usually
+sent from server to client, however, server may send it to another
+server as well. Client must not send this payload. The receiver of
+this payload may totally ignore the contents of the payload, however,
+notify message should be noted and possibly logged.
+
+The payload may only be sent with SILC_PACKET_NOTIFY packet. It must
+not be sent in any other packet type. Following diagram represents the
+Notify Payload.
+
+
+
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Notify Message ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 7: Notify Payload
+
+
+.in 6
+o Notify Message (variable length) - Human readable notify
+ message.
+.in 3
+
+
+.ti 0
+2.3.7 Error Payload
+
+Error payload is sent upon error. Error may occur in various
+conditions when server sends this packet. Client may not send this
+payload but must be able to accept it. However, client may
+totally ignore the contents of the packet as server is going to
+take action on the error anyway. However, it is recommended
+that the client takes error packet seriously.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Error Message ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 8: Error Payload
+
+
+.in 6
+o Error Message (variable length) - Human readable error
+ message.
+.in 3
+
+
+.ti 0
+2.3.8 Channel Message Payload
+
+Channel messages are the most common messages sent in the SILC.
+Channel Message Payload is used to send message to channels. These
+messages can only be sent if client has joined to some channel.
+Even though this packet is the most common in SILC it is still
+special packet. Some special handling on sending and reception
+of channel message is required.
+
+Padding must be applied into this payload since the payload is
+encrypted separately from other parts of the packet with the
+channel specific key. Hence the requirement of the padding.
+The padding should be random data. The packet must be made
+multiple by eight (8) or by the block size of the cipher, which
+ever is larger.
+
+The SILC header in this packet is encrypted with the session key
+of the next receiver of the packet. Nothing else is encrypted
+with that key. Hence, the actual packet and padding to be
+encrypted with the session key is SILC Header plus padding to it
+to make it multiple by eight (8) or multiple by the block size
+of the cipher, which ever is larger.
+
+Receiver of the the channel message packet is able to determine
+the channel the message is destined to by checking the destination
+ID from the SILC Packet header which tells the destination channel.
+The original sender of the packet is also determined by checking
+the source ID from the header which tells the who client sent
+the message.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_MESSAGE packet.
+It must not be sent in any other packet type. Following diagram
+represents the Notify Payload.
+
+(*) indicates that the field is not encrypted.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Nickname Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Nickname ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Message Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Message Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Padding Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Padding ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Initial Vector * ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 9: Channel Message Payload
+
+
+.in 6
+o Nickname Length (2 bytes) - Indicates the length of the
+ Nickname field, not including any other field.
+
+o Nickname (variable length) - Nickname of the sender of the
+ channel message. This should not be trusted as a definite
+ sender of the channel message. The SILC Packet Header in
+ the packet indicates the true sender of the packet and
+ client should verify that the nickname sent here belongs
+ to the Client ID in the SILC Packet Header. This nickname
+ is merely provided to be displayed by the client.
+
+ If server is sending this packet this field is not included
+ and zero (0) length must be set to the Nickname Length field.
+
+o Message Length (2 bytes) - Indicates the length of the
+ the Message Data field in the payload, not including any
+ other field.
+
+
+o Message Data (variable length) - The actual message to
+ the channel.
+
+o Padding Length (2 bytes) - Indicates the length of the
+ Padding field in the payload, not including any other
+ field.
+
+o Padding (variable length) - The padding that must be
+ applied because this payload is encrypted separately from
+ other parts of the packet.
+
+o Initial Vector (variable length) - The initial vector
+ that has been used in packet encryption. It needs to be
+ used in the packet decryption as well. What this field
+ includes is implementation issue. However, it is
+ recommended that it would be random data or, perhaps,
+ a timestamp. It is not recommended to use zero (0) as
+ initial vector. This field is not encrypted. This field
+ is not included into the padding calculation. Length
+ of this field equals the cipher's block size. This field
+ is, however, authenticated.
+.in 3
+
+
+.ti 0
+2.3.9 Channel Key Payload
+
+All traffic in channels are protected by channel specific keys.
+Channel Key Payload is used to distribute channel keys to all
+clients on the particular channel. Channel keys are sent when
+the channel is created, when new user joins to the channel and
+whenever a user leaves a channel. Server creates the new
+channel key and distributes it to the clients by encrypting this
+payload with the session key shared between the server and
+the client. After that, client starts using the key received
+in this payload to protect the traffic on the channel.
+
+Channel keys are cell specific thus every router in cell have
+to create a channel key and distribute it if any client in the
+cell has joined to a channel. Channel traffic between cell's
+are not encrypted using channel keys, they are encrypted using
+normal session keys between two routers. Inside a cell, all
+channel traffic is encrypted with the specified channel key.
+Channel key should expire peridiocally, say, in one hour, in
+which case new channel key is created and distributed.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_KEY packet.
+It must not be sent in any other packet type. Following diagram
+represents the Channel Key Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Channel ID Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Channel ID ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Cipher Name Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Cipher Name ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Channel Key Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Channel Key ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 10: Channel Key Payload
+
+
+
+.in 6
+o Channel ID Length (2 bytes) - Indicates the length of the
+ Channel ID field in the payload, not including any other
+ field.
+
+o Channel ID (variable length) - The Channel ID of the
+ channel this key is meant for.
+
+o Cipher Name Length (2 bytes) - Indicates the length of the
+ Cipher name field in the payload, not including any other
+ field.
+
+o Cipher Name (variable length) - Name of the cipher used
+ in the protection of channel traffic. This name is
+ initially decided by the creator of the channel but it
+ may change during the life time of the channel as well.
+
+o Channel Key Length (2 bytes) - Indicates the length of the
+ Channel Key field in the payload, not including any other
+ field.
+
+o Channel Key (variable length) - The actual channel key
+ material. This key is used as such as key material for
+ encryption function.
+.in 3
+
+
+.ti 0
+2.3.10 Private Message Payload
+
+Private Message Payload is used to send private message between
+two clients (or users for that matter). The messages are sent only
+to the specified user and no other user inside SILC network is
+able to see the message. The message is protected by the session
+key established by the SILC Key Exchange Protocol. However,
+it is also possible to agree to use specific keys to protect
+just the private messages. See section 2.3.11 Private Message
+Key Payload for detailed description of how to agree to use
+specific key.
+
+If normal session key is used to protect the message, every
+server between the sender client and the receiving client needs
+to decrypt the packet and always re-encrypt it with the session
+key of the next receiver of the packet. See section Client
+To Client in [SILC1].
+
+When specific key is used to protect the message, servers between
+the sender and the receiver needs not to decrypt/re-encrypt the
+packet. Section 4.8.2 Client To Client in [SILC1] gives example of
+this scheme as well.
+
+The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE
+packet. It must not be sent in any other packet type. Following
+diagram represents the Private Message Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Nickname Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Nickname ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Message Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 11: Private Message Payload
+
+
+.in 6
+o Nickname Length (2 bytes) - Indicates the length of the
+ Nickname field, not including any other field.
+
+o Nickname (variable length) - Nickname of the sender of the
+ private message. This should not be trusted as a definite
+ sender of the private message. The SILC Packet Header in
+ the packet indicates the true sender of the packet and
+ client should verify that the nickname sent here belongs
+ to the Client ID in the SILC Packet Header. This nickname
+ is merely provided to be displayed by the client.
+
+o Message Data (variable length) - The actual message to
+ the client. Rest of the packet is reserved for the message
+ data.
+.in 3
+
+
+.ti 0
+2.3.11 Private Message Key Payload
+
+This payload is used to send key from client to another client that
+is going to be used to protect the private messages between these
+two clients. If this payload is not sent normal session key
+established by the SILC Key Exchange Protocol is used to protect
+the private messages.
+
+This payload may only be sent by client to another client. Server
+must not send this payload at any time. After sending this payload
+the sender of private messages must set the Private Message Key
+flag into SILC Packet Header.
+
+The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE_KEY
+packet. It must not be sent in any other packet type. Following
+diagram represents the Private Message Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Private Message Key Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Private Message Key ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 12: Private Message Key Payload
+
+
+
+
+.in 6
+o Private Message Key Length (2 bytes) - Indicates the length
+ of the Private Message Key field in the payload, not including
+ any other field.
+
+o Private Message Key (variable length) - The actual private
+ message key material. This key is used as such as key material
+ for encryption function.
+.in 3
+
+
+.ti 0
+2.3.12 Command Payload
+
+Command Payload is used to send SILC commands from client to server.
+Following diagram represents the Command Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| SILC Command | Arguments Num | Payload Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 13: Command Payload
+
+
+.in 6
+o SILC Command (1 byte) - SILC Command identifier. This must
+ be set to non-zero value. If zero (0) value is found in this
+ field the packet must be discarded.
+
+o Arguments Num (1 byte) - Indicates the number of arguments
+ associated with the command. If there are no arguments this
+ field is set to zero (0). The arguments must follow the
+ command payload.
+
+o Payload Length (2 bytes) - Length of the entire command
+ payload including any command argument payloads associated
+ with this payload.
+.in 3
+
+See [SILC1] for detailed description of different SILC commands,
+their arguments and their reply messages.
+
+
+.ti 0
+2.3.12.1 Command Argument Payload
+
+Command Argument Payload is used to set arguments for SILC commands.
+Number of arguments associated with a command are indicated by the
+Command Payload in the Arguments Num field. Command argument
+payloads may only be used with a command payload and they must
+always reside right after the command payload. Incorrect amount of
+argument payloads must cause rejection of the packet. Following
+diagram represents the Command Argument Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Argument Num | Argument Type | Payload Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Argument Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 14: Command Argument Payload
+
+
+.in 6
+o Argument Num (1 byte) - Indicates the number of this argument.
+ For first argument this is set to 1, for second argument this
+ is set to 2, and so forth. If incorrect value is found
+ in this field the packet must be discarded. Value is
+ incorrect if it is zero (0) or, for example, a third argument
+ does not include value 3.
+
+o Argument Type (1 byte) - Indicates the type of the argument.
+ Every command specify a number for each argument that maybe
+ associated with the command. By using this number the receiver
+ of the packet knows what type of argument this is. The numbers
+ are command specific and has been defined in section SILC
+ Commands in [SILC1]. This field makes it possible to send
+ arguments in free order as this field is used to identify
+ the specific type of the argument.
+
+o Payload Length (2 bytes) - Length of the argument payload data
+ area not including the length of any other fields in the
+ payload.
+
+o Argument Data (variable length) - Argument data.
+.in 3
+
+
+.ti 0
+2.3.13 Command Reply Payload
+
+Command Reply Payload is used to send replies to the commands sent
+by the client. The Command Reply Payload is identical to the
+Command Payload hence see the upper sections for Command Payload
+and for Command Argument Payload specifications. Command Reply
+message uses the Command Argument Payload as well.
+
+See SILC Commands in [SILC1] for detailed description of different
+SILC commands, their arguments and their reply messages.
+
+
+.ti 0
+2.3.14 Connection Auth Request Payload
+
+Client may send this payload to server to request the authentication
+method that must be used in authentication protocol. If client knows
+this information beforehand this payload is not necessary to be sent.
+Server performing authentication with another server may also send
+this payload to request the authentication method. If the connecting
+server already knows this information this payload is not necessary
+to be sent.
+
+Server receiving this request must reply with same payload sending
+the mandatory authentication method. Algorithms that may be required
+to be used by the authentication method are the ones already
+established by the SILC Key Exchange protocol. See section Key
+Exchange Start Payload in [SILC3] for detailed information.
+
+The payload may only be sent with SILC_PACKET_CONNECTION_AUTH_REQUEST
+packet. It must not be sent in any other packet type. Following
+diagram represents the Connection Auth Request Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Connection Type | Authentication Method |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 15: Connection Auth Request Payload
+
+
+.in 6
+o Connection Type (2 bytes) - Indicates the type of the ID.
+ Following connection types are defined:
+
+ 1 Client connection
+ 2 Server connection
+ 3 Router connection
+
+ If any other type is found in this field the packet must be
+ discarded and the authentication must be failed.
+
+o Authentication Method (2 bytes) - Indicates the authentication
+ method to be used in the authentication protocol. Following
+ authentication methods are defined:
+
+
+
+ 0 NONE (mandatory)
+ 1 password (mandatory)
+ 2 public key (mandatory)
+
+ If any other type is found in this field the packet must be
+ discarded and the authentication must be failed. If this
+ payload is sent as request to receive the mandatory
+ authentication method this field must be set to zero (0),
+ indicating that receiver should send the mandatory
+ authentication method. The receiver sending this payload
+ to the requesting party, may also set this field to zero (0)
+ to indicate that authentication is not required. In this
+ case authentication protocol still must be started but
+ server is most likely to respond with SILC_PACKET_SUCCESS
+ immediately.
+.in 3
+
+
+.ti 0
+2.3.15 New ID Payload
+
+New ID Payload is a multipurpose payload. It is used to send newly
+created ID's from clients and servers. When client connects to server
+and registers itself to the server by sending SILC_PACKET_NEW_CLIENT
+packet, server replies with this packet by sending the created ID for
+the client. Server always creates the ID for the client.
+
+This payload is also used when server tells its router that new client
+has registered to the SILC network. In this case the server sends
+the Client ID of the client to the router. Similiary when router
+distributes information to other routers about the client in the SILC
+network this payload is used.
+
+Also, when server connects to router, router uses this payload to inform
+other routers about new server in the SILC network. However, every
+server (or router) creates their own ID's thus the ID distributed by
+this payload is not created by the distributor in this case. Servers
+create their own ID's. Server registers itself to the network by sending
+SILC_PACKET_NEW_SERVER to the router it connected to. The case is same
+when router connects to another router.
+
+Hence, this payload is very important and used every time when some
+new entity is registered to the SILC network. Client never sends this
+payload. Both client and server (and router) may receive this payload.
+
+The payload may only be sent with SILC_PACKET_NEW_ID packet. It must
+not be sent in any other packet type. Following diagram represents the
+New ID Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| ID Type | ID Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ ID Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 16: New ID Payload
+
+
+.in 6
+o ID Type (2 bytes) - Indicates the type of the ID. See
+ section 2.4 SILC ID Types for list of defined ID types.
+
+o ID Length (2 bytes) - Length of the ID Data area not
+ including the length of any other fields in the payload.
+
+o ID Data (variable length) - The actual ID data.
+.in 3
+
+
+
+.ti 0
+2.3.16 New ID List Payload
+
+New ID List Payload is used to distribute list of ID's usually from
+server to router but also from router to other routers in the network.
+This payload is used, for example, when server is connected to router
+and the server wants to distribute all of its locally connected clients
+and locally created channels to the router. It is convenient in this
+case to use this payload instead of sending all the information one
+by one using New ID Payload.
+
+There is no specific payload for this packet type. The packet type
+uses same payload as described in previous section. To form a list
+several payloads is put in the packet each after each. The payload
+is variable in length but can be calculated by calculating the ID
+Type field, Length field and the ID Data fields together. This forms
+one New ID Payload in the list.
+
+The list of payloads may only be sent with SILC_PACKET_NEW_ID_LIST
+packet. They must not be sent in any other packet type.
+
+
+.ti 0
+2.3.17 New Client Payload
+
+When client is connected to the server, keys has been exchanged and
+connection has been authenticated client must register itself to the
+server. Clients first packet after key exchange and authentication
+protocols must be SILC_PACKET_NEW_CLIENT. This payload tells server all
+the relevant information about the connected user. Server creates a new
+client ID for the client when received this payload and sends it to the
+client in New ID Payload.
+
+This payload sends username and real name of the user on the remote host
+which is connected to the SILC server with SILC client. The server
+creates the client ID according the information sent in this payload.
+The nickname of the user becomes the username sent in this payload.
+However, client should call NICK command after sending this payload to
+set the real nickname of the user which is then used to create new
+client ID.
+
+The payload may only be sent with SILC_PACKET_NEW_CLIENT packet. It
+must not be sent in any other packet type. Following diagram represents
+the New Client Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Username Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Username ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Real Name Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Real Name ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 17: New Client Payload
+
+
+.in 6
+o Username Length (2 bytes) - Length of the username.
+
+o Username (variable length) - The username of the user on
+ the host where connecting to the SILC server.
+
+o Real Name Length (2 bytes) - Length of the Real Name.
+
+o Real Name (variable length) - The real name of the user
+ on the host where connecting to the SILC server.
+.in 3
+
+
+.ti 0
+2.3.18 New Server Payload
+
+This payload is sent by server when it has completed successfully both
+key exchange and connection authentication protocols. The server
+uses this payload to register itself to the SILC network. The
+first packet after these key exchange and authentication protocols
+is SILC_PACKET_NEW_SERVER packet. The payload includes the Server ID
+of the server that it has created by itself. It also includes a
+name of the server that is associated to the Server ID.
+
+The payload may only be sent with SILC_PACKET_NEW_SERVER packet. It
+must not be sent in any other packet type. Following diagram represents
+the New Server Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Server ID Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Server ID Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Server Name Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Server Name ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 18: New Server Payload
+
+
+.in 6
+o Server ID Length (2 bytes) - Length of the ID Data area not
+ including the length of any other fields in the payload.
+
+o Server ID Data (variable length) - The actual Server ID
+ data.
+
+o Server Name Length (2 bytes) - Length of the server name.
+
+o Server Name (variable length) - The server name.
+.in 3
+
+
+.ti 0
+2.3.19 New Channel Payload
+
+Information about newly created channel is broadcasted to all routers
+in the SILC network by sending this packet payload. Channels are
+created by router of the cell. Server never creates channels unless
+it is a standalone server and it does not have router connection,
+in this case server acts as router. Normal server sends JOIN command
+to the router (after it has received JOIN command from client) which
+then processes the command and creates the channel. Client never sends
+this packet.
+
+The payload may only be sent with SILC_PACKET_NEW_CHANNEL packet.
+It must not be sent in any other packet type. Following diagram
+represents the New Channel Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Channel Name Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Channel Name ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Channel ID Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Channel ID ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 19: New Channel Payload
+
+
+
+.in 6
+o Channel Name Length (2 bytes) - Length of the channel name.
+
+o Channel Name (variable length) - The name of the created
+ channel.
+
+o Channel ID Length (2 bytes) - Length of the Channel ID.
+
+o Channel ID (variable length) - The created Channel ID.
+.in 3
+
+
+.ti 0
+2.3.20 New Channel User Payload
+
+When client (user) joins to a channel, server must notify routers
+about the new user on the channel. Normal server sends this packet
+payload to its router which then broadcasts the packet further.
+Router sends this packet always to its primary router. Client must
+not send this packet payload. The mode of the user is NONE after
+user has joined to the channel.
+
+The payload may only be sent with SILC_PACKET_NEW_CHANNEL_USER
+packet. It must not be sent in any other packet type. Following
+diagram represents the New Channel User Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Channel ID Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Channel ID ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Client ID Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Client ID ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 20: New Channel User Payload
+
+
+.in 6
+o Channel ID Length (2 bytes) - Length of the Channel ID.
+
+o Channel ID (variable length) - The Channel ID of the channel
+ to which the client has joined.
+
+o Client ID Length (2 bytes) - Length of the Client ID.
+
+o Client ID (variable length) - The Client ID of the client
+ who has joined the channel.
+.in 3
+
+
+.ti 0
+2.3.21 New Channel List Payload
+
+This payload is used to distribute list of new channels from server
+to routers. It might convenient to send list of new channels when
+existing server connects to router, instead of sending them one
+by one.
+
+There is no specific payload for this packet type. The packet type
+uses same payload as described in 2.3.19 New Channel Payload. To form
+a list several payloads is put in the packet each after each. The
+payload is variable in length but can be calculated by calculating
+the length of the fields together. This forms one New Channel Payload
+in the list.
+
+The list of payloads may only be sent with SILC_PACKET_NEW_CHANNEL_LIST
+packet. They must not be sent in any other packet type.
+
+
+.ti 0
+2.3.22 New Channel User List Payload
+
+This payload is used to distribute list of channel users on specific
+channel from server to routers. It might convenient to send list of
+channel users when existing server connects to router, instead of
+sending them one by one.
+
+There is no specific payload for this packet type. The packet type
+uses same payload as described in 2.3.20 New Channel User Payload.
+To form a list several payloads is put in the packet each after each.
+The payload is variable in length but can be calculated by calculating
+the length of the fields together. This forms one New Channel User
+Payload in the list.
+
+The list of payloads may only be sent with packet
+SILC_PACKET_NEW_CHANNEL_USER_LIST. They must not be sent in any other
+packet type.
+
+
+.ti 0
+2.3.23 Replace ID Payload
+
+This payload is used to replace old ID with new ID sent in the payload.
+When ID changes for some entity and the new ID is wanted to replace the
+old one this payload must be used. Client cannot send or receive this
+payload. Normal server and router server may send and receive this
+payload. After this packet has been sent the old ID must not be used
+anymore.
+
+The payload may only be sent with SILC_PACKET_REPLACE_ID packet. It must
+not be sent in any other packet type. Following diagram represents the
+Replace Payload Payload.
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Old ID Type | Old ID Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Old ID Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| New ID Type | New ID Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ New ID Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 21: Replace ID Payload
+
+
+.in 6
+o Old ID Type (2 bytes) - Indicates the type of the old ID. See
+ section 2.4 SILC ID Types for list of defined ID types.
+
+o Old ID Length (2 bytes) - Length of the old ID Data area not
+ including the length of any other fields in the payload.
+
+o Old ID Data (variable length) - The actual old ID data.
+
+o New ID Type (2 bytes) - Indicates the type of the new ID. See
+ section 2.4 SILC ID Types for list of defined ID types.
+
+o New ID Length (2 bytes) - Length of the new ID Data area not
+ including the length of any other fields in the payload.
+
+o New ID Data (variable length) - The actual new ID data.
+.in 3
+
+
+.ti 0
+2.3.24 Remove ID Payload
+
+Remove ID payload is used to remove ID from SILC network. This is used
+for example when client exits SILC network. The server must in this
+case send this payload to notify that this ID is not valid anymore.
+After this has been send the old ID must not be used anymore. Client
+must not send this payload.
+
+The payload may only be sent with SILC_PACKET_REMOVE_ID packet. It must
+not be sent in any other packet type. Following diagram represents the
+Remove Payload Payload.
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| ID Type | ID Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ ID Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 22: Remove ID Payload
+
+
+.in 6
+o ID Type (2 bytes) - Indicates the type of the ID to be
+ removed. See section 2.4 SILC ID Types for list of defined
+ ID types.
+
+o ID Length (2 bytes) - Length of the D Data area not including
+ the length of any other fields in the payload.
+
+o ID Data (variable length) - The actual ID data to be removed.
+.in 3
+
+
+.ti 0
+2.4 SILC ID Types
+
+ID's are extensively used in the SILC network to associate different
+entities. Following ID's has been defined to be used in the SILC
+network.
+
+.in 6
+0 No ID
+
+ When ever specific ID cannot be used this is used.
+
+1 Server ID
+
+ Server ID to associate servers. See the format of
+ this ID in [SILC1].
+
+2 Client ID
+
+ Client ID to associate clients. See the format of
+ this ID in [SILC1].
+
+3 Channel ID
+
+ Channel ID to associate channels. See the format of
+ this ID in [SILC1].
+.in 3
+
+
+.ti 0
+2.5 Packet Encryption And Decryption
+
+SILC packets are encrypted almost entirely. Only small part of SILC
+header is not encrypted as described in section 5.2 SILC Packet Header.
+The SILC Packet header is the first part of a packet to be encrypted
+and it is always encrypted with the key of the next receiver of the
+packet. The data payload area of the packet is always entirely
+encrypted and it is usually encrypted with the next receiver's key.
+However, there are some special packet types and packet payloads
+that require special encryption process. These special cases are
+described in the next sections. First is described the normal packet
+encryption process.
+
+
+.ti 0
+2.5.1 Normal Packet Encryption And Decryption
+
+Normal SILC packets are encrypted with the session key of the next
+receiver of the packet. The entire SILC Packet header and the packet
+data payload is is also encrypted with the same key. Padding of the
+packet is also encrypted always with the session key, also in special
+cases. Computed MAC of the packet must not be encrypted.
+
+Decryption process in these cases are straightforward. The receiver
+of the packet must first decrypt the SILC Packet header, or some parts
+of it, usually first 16 bytes of it. Then the receiver checks the
+packet type from the decrypted part of the header and can determine
+how the rest of the packet must be decrypted. If the packet type is
+any of the special cases described in following sections the packet
+decryption is special. If the packet type is not among those special
+packet types rest of the packet may be decrypted with the same key.
+
+Also, note that two bytes of the SILC Packet header are not encrypted
+thus it must be noticed in the decryption process by starting the
+decryption from the second byte of the header. This sets some rules
+to padding generation as well, see the section 2.7 Packet Padding
+Generation.
+
+With out a doubt, this sort of decryption processing causes some
+overhead to packet decryption, but never the less, is required.
+
+
+.ti 0
+2.5.2 Channel Message Encryption And Decryption
+
+Channel Messages (Channel Message Payload) are always encrypted with
+the channel specific key. However, the SILC Packet header is not
+encrypted with that key. As in normal case, the header is encrypted
+with the key of the next receiver of the packet, who ever that might
+be. Note that in this case the encrypted data area is not touched
+at all; it must not be re-encrypted with the session key.
+
+Receiver of a channel message, who ever that is, is required to decrypt
+the SILC Packet header to be able to even recognize the packet to be as
+channel message. This is same procedure as for normal SILC packets.
+As the receiver founds the packet to be channel message, rest of the
+packet processing is special. Rest of the SILC Packet header is
+decrypted with the same session key along with the padding of the
+packet. After that the packet is protected with the channel specific
+key and hence can be decrypted only if the receiver is the client on
+the channel. See section 2.7 Packet Padding Generation for more
+information about padding on special packets.
+
+If the receiver of the channel message is router who is routing the
+message to another router then it must decrypt the Channel Message
+payload. Between routers (that is, between cells) channel messages
+are protected with session keys shared between the routers. This
+causes another special packet processing for channel messages. If
+the channel message is received from another router then the entire
+packet, including Channel Message payload, is encrypted with the
+session key shared between the routers. In this case the packet
+decryption process is as with normal SILC packets. Hence, if the
+router is sending channel message to another router the Channel
+Message payload must have been decrypted and must be re-encrypted
+with the session key shared between the another router. In this
+case the packet encryption is as with any normal SILC packet.
+
+It must be noted that this is only when the channel messages are sent
+from router to another router. In all other cases the channel
+message encryption and decryption is as described above. This
+different processing of channel messages with router to router
+connection is because channel keys are cell specific. All cells has
+their own channel keys thus the channel message traveling from one
+cell to another must be protected as it would be any normal SILC
+packet.
+
+
+.ti 0
+2.5.3 Private Message Encryption And Decryption
+
+By default, private message in SILC are protected by session keys.
+In this case the private message encryption and decryption process is
+equivalent to normal packet encryption and decryption.
+
+However, private messages can be protected with private message key
+which causes the packet to be special packet. The procedure in this
+case is very much alike to channel packets. The actual private message
+is encrypted with the private message key and other parts of the
+packet is encrypted with the session key. See 2.7 Packet Padding
+Generation for more information about padding on special packets.
+
+The difference from channel message processing is that server or router
+en route never decrypts the actual private message, as it does not
+have the key to do that. Thus, when sending packets between router
+the processing is same as in any other case as well; the packet's header
+and padding is protected by the session key and the data area is not
+touched.
+
+The true receiver of the private message, client, that is, is able
+to decrypt the private message as it shares the key with the sender
+of the message.
+
+
+.ti 0
+2.6 Packet MAC Generation
+
+Data integrity of a packet is protected by including a message
+authentication code (MAC) at the end of the packet. The MAC is computed
+from shared secret MAC key, that is established by the SILC Key Exchange
+protocol, and from the original contents of the packet. The MAC is
+always computed before the packet is encrypted, although after it is
+compressed if compression is used.
+
+The MAC is computed from entire packet. Every bit of data in the packet,
+including SILC Packet Header is used in the MAC computing. This way
+the entire packet becomes authenticated.
+
+If the packet is special packet MAC is computed from the entire packet
+but part of the packet may be encrypted before the MAC is computed.
+This is case, for example, with channel messages where the message data
+is encrypted with key that server may not now. In this case the MAC
+has been computed from the encrypted data.
+
+See [SILC1] for defined and allowed MAC algorithms.
+
+
+.ti 0
+2.7 Packet Padding Generation
+
+Padding is needed in the packet because the packet is encrypted. It
+must always be multiple by eight (8) or multiple by the size of the
+cipher's block size, which ever is larger. The padding is always
+encrypted.
+
+For normal packets the padding is added after the SILC Packet Header
+and between the Data Payload area. The padding for normal packets
+are calculated as follows:
+
+.in 6
+padding length = 16 - ((packet length - 2) % 16)
+.in 3
+
+The 16 is the maximum padding allowed in SILC packet. Two (2) is
+subtracted from the true length of the packet because two (2) bytes
+is not encrypted in SILC Packet Header, see section 2.2 SILC Packet
+Header. Those two bytes that are not encrypted must not be calculated
+to the padding length.
+
+For special packets the padding calculation may be different as special
+packets may be encrypted differently. In these cases the encrypted
+data area must already be multiple by the block size thus in this case
+the padding is calculated only for SILC Packet Header, not for any
+other area of the packet. The same algorithm works in this case as
+well, except that the `packet length' is now the SILC Packet Header
+length. In this case, as well, two (2) is subtracted from the
+length.
+
+The padding must be random data, preferably, generated by
+cryptographically strong random number generator.
+
+
+.ti 0
+2.8 Packet Compression
+
+SILC Packets may be compressed. In this case the data payload area
+is compressed and all other areas of the packet must remain as they
+are. After compression is performed for the data area, the length
+field of Packet Header must be set to the compressed length of the
+data.
+
+The compression must always be applied before encryption. When
+the packet is received and decrypted the data area must be decompressed.
+Note that the true sender of the packet must apply the compression and
+the true receiver of the packet must apply the decompression. Any
+server or router en route must not decompress the packet.
+
+
+.ti 0
+2.9 Packet Sending
+
+The sender of the packet must assemble the SILC Packet Header with
+correct values. It must set the Source ID of the header as its own
+ID. It must also set the Destination ID of the header to the true
+destination. If the destination is client it will be Client ID, if
+it is server it will be Server ID and if it is channel it will be
+Channel ID.
+
+If the sender wants to compress the packet it must apply the
+compression now. Sender must also compute the padding as described
+in above sections. Then sender must compute the MAC of the packet.
+
+Then sender encrypts the packet as has been described in above
+sections according whether the packet is normal packet or special
+packet. The computed MAC must not be encrypted.
+
+
+.ti 0
+2.10 Packet Reception
+
+On packet reception the receiver must check that all fields in the
+SILC Packet Header are valid sain. It must check the flags of the
+header and act accordingly. It must also check the MAC of the packet
+and if it is to be failed the packet must be discarded. Also if the
+header of the packet includes any bad fields the packet must be
+discarded.
+
+See above sections on the decryption process of the received packet.
+
+The receiver must also check that the ID's in the header are valid
+ID's. Unsupported ID types or malformed ID's must cause packet
+rejection. The padding on the reception is always ignored.
+
+The receiver must also check the packet type and start parsing the
+packet according to the type. However, note the above sections on
+special packet types and their parsing.
+
+
+.ti 0
+2.11 Packet Broadcasting
+
+SILC packets may be broadcasted in SILC network. However, only router
+server may send or receive broadcast packets. Client and normal server
+must not send broadcast packets and they must ignore broadcast packets
+if they receive them. Broadcast packets are sent by setting Broadcast
+flag to the SILC packet header.
+
+Broadcasting packets means that the packet is sent to all routers in
+the SILC network, except to the router that sent the packet. The router
+receiving broadcast packet must send the packet to its primary route.
+The fact that SILC routers may have several router connections may
+cause problems, such as race conditions inside the SILC network, if
+care is not taken when broadcasting packets. Router must not send
+the broadcast packet to any other route except to its primary route.
+
+If the primary route of the router is the original sender of the packet
+the packet must not be sent to the primary route. This may happen
+if router has several router connections and some other router uses
+the router as its primary route.
+
+Routers use broadcast packets to broadcast for example information
+about newly registered clients, servers, channels etc. so that all the
+routers may keep these informations up to date.
+
+
+.ti 0
+2.12 Packet Routing
+
+Routers are the primary entities in the SILC network that takes care
+of packet routing. However, normal servers routes packets as well, for
+example, when they are routing channel message to the local clients.
+Routing is quite simple as every packet tells the true origin and the
+true destination of the packet.
+
+It is still recommended for routers that has several routing connections
+to create route cache for those destinations that has faster route than
+the router's primary route. This information is available for the router
+when other router connects to the router. The connecting party then
+sends all of its locally connected clients, server and channels. These
+informations helps to create the route cache. Also, when new channels
+are created to a cell its information is broadcasted to all routers
+in the network. Channel ID's are based on router's ID thus it is easy
+to create route cache based on these informations. If faster route for
+destination does not exist in router's route cache the packet must be
+routed to the primary route (default route).
+
+For server who receives a packet to be routed to its locally connected
+client the server must check whether the particular packet type is
+allowed to be routed to the client. Not all packets may be sent by
+some odd entity to client that is indirectly connected to the sender.
+See section 2.3 SILC Packet Types and paragraph about indirectly connected
+entities and sending packets to them. The section mentions the packets
+that may be sent to indirectly connected entities. It is clear that some
+server cannot send, for example, disconnect packet to client that is not
+directly connected to the server.
+
+
+.ti 0
+2.13 Packet Tunneling
+
+Tunneling is a feature that is available in SILC protocol. Tunneling
+means that extra SILC Packet Header is applied to the original packet
+and thus hiding the original packet entirely. There can be some
+interesting applications using tunneling, such as, using ID's based on
+private network IP addresses inside in the tunneled packet. This can
+open many interesting features relating to connecting to private network
+from the Internet with SILC and many more. However, this feature is
+optional currently in SILC as there does not exist thorough analysis of
+this feature. It is with out a doubt that there will be many more
+applications that has not yet been discovered. Thus, it is left
+to Internet Community to investigate the use of tunneling in SILC
+protocol. This document is updated according those investigations
+and additional documents on the issue may be written.
+
+
+.ti 0
+3 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+4 References
+
+[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
+ Protocol Specification", Internet Draft, June 2000.
+
+[SILC3] Riikonen, P., "SILC Key Exchange and Authentication
+ Protocols", Internet Draft, June 2000.
+
+[IRC] Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+ RFC 1459, May 1993.
+
+[SSH-TRANS] Ylonen, T., et al, "SSH Transport Layer Protocol",
+ Internet Draft.
+
+[PGP] Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+ November 1998.
+
+[SPKI] Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+ September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+ Infrastructure, Certificate and CRL Profile", RFC 2459,
+ January 1999.
+
+[Schneier] Schneier, B., "Applied Cryptography Second Edition",
+ John Wiley & Sons, New York, NY, 1996.
+
+[Menezes] Menezes, A., et al, "Handbook of Applied Cryptography",
+ CRC Press 1997.
+
+[OAKLEY] Orman, H., "The OAKLEY Key Determination Protocol",
+ RFC 2412, November 1998.
+
+[ISAKMP] Maughan D., et al, "Internet Security Association and
+ Key Management Protocol (ISAKMP)", RFC 2408, November
+ 1998.
+
+[IKE] Harkins D., and Carrel D., "The Internet Key Exhange
+ (IKE)", RFC 2409, November 1998.
+
+[HMAC] Krawczyk, H., "HMAC: Keyed-Hashing for Message
+ Authentication", RFC 2104, February 1997.
+
+
+.ti 0
+5 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
--- /dev/null
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 27 June 2000
+.ds CH Secure Internet Live Conferencing
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group P. Riikonen
+Internet-Draft
+draft-riikonen-silc-spec-00.txt 27 June 2000
+Expires: 27 Jan 2001
+
+.in 3
+
+.ce 2
+Secure Internet Live Conferencing (SILC),
+Protocol Specification
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other
+documents at any time. It is inappropriate to use Internet-Drafts
+as reference material or to cite them other than as
+``work in progress.''
+
+To learn the current status of any Internet-Draft, please check the
+``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes a Secure Internet Live Conferencing (SILC)
+protocol which provides secure conferencing services over insecure
+network channel. SILC is IRC [IRC] like protocol, however, it is
+not equivalent to IRC and does not support IRC. Strong cryptographic
+methods are used to protect SILC packets inside SILC network. Two
+other Internet Drafts relates very closely to this memo; SILC Packet
+Protocol [SILC2] and SILC Key Exchange and Authentication Protocols
+[SILC3].
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction .................................................. 3
+2 SILC Concepts ................................................. 3
+ 2.1 SILC Network Topology ..................................... 4
+ 2.2 Communication Inside a Cell ............................... 5
+ 2.3 Communication in the Network .............................. 6
+ 2.4 Channel Communication ..................................... 7
+3 SILC Specification ............................................ 7
+ 3.1 Client .................................................... 7
+ 3.1.1 Client ID ........................................... 8
+ 3.2 Server .................................................... 8
+ 3.2.1 Server's Local ID List .............................. 9
+ 3.2.2 Server ID ........................................... 10
+ 3.2.3 SILC Server Ports ................................... 10
+ 3.3 Router .................................................... 11
+ 3.3.1 Router's Local ID List .............................. 11
+ 3.3.2 Router's Global ID List ............................. 12
+ 3.3.3 Router's Server ID .................................. 12
+ 3.4 Channels .................................................. 12
+ 3.4.1 Channel ID .......................................... 13
+ 3.5 Operators ................................................. 14
+ 3.6 SILC Commands ............................................. 14
+ 3.7 SILC Packets .............................................. 15
+ 3.8 Packet Encryption ......................................... 15
+ 3.8.1 Determination of the Source and the Destination ..... 16
+ 3.8.2 Client To Client .................................... 16
+ 3.8.3 Client To Channel ................................... 17
+ 3.8.4 Server To Server .................................... 18
+ 3.9 Key Exchange And Authentication ........................... 18
+ 3.10 Algorithms ............................................... 19
+ 3.10.1 Ciphers ............................................ 19
+ 3.10.2 Public Key Algorithms .............................. 20
+ 3.10.3 MAC Algorithms ..................................... 20
+ 3.10.4 Compression Algorithms ............................. 20
+ 3.11 SILC Public Key .......................................... 21
+4 SILC Procedures ............................................... 23
+ 4.1 Creating Client Connection ................................ 23
+ 4.2 Creating Server Connection ................................ 24
+ 4.3 Joining to a Channel ...................................... 25
+ 4.4 Channel Key Generation .................................... 26
+ 4.5 Private Message Sending and Reception ..................... 27
+ 4.6 Private Message Key Generation ............................ 27
+ 4.7 Channel Message Sending and Reception ..................... 28
+ 4.8 Session Key Regeneration .................................. 28
+ 4.9 Command Sending and Reception ............................. 29
+5 SILC Commands ................................................. 29
+ 5.1 SILC Commands Syntax ...................................... 29
+ 5.2 SILC Commands List ........................................ 31
+ 5.3 SILC Command Status Types ................................. 53
+ 5.3.1 SILC Command Status Payload ......................... 53
+ 5.3.2 SILC Command Status List ............................ 54
+6 Security Considerations ....................................... 58
+7 References .................................................... 58
+8 Author's Address .............................................. 59
+
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1: SILC Network Topology
+Figure 2: Communication Inside cell
+Figure 3: Communication Between Cells
+Figure 4: SILC Public Key
+Figure 5: SILC Command Status Payload
+
+
+.ti 0
+1. Introduction
+
+This document describes a Secure Internet Live Conferencing (SILC)
+protocol which provides secure conferencing services over insecure
+network channel. SILC is IRC [IRC] like protocol, however, it is
+not equivalent to IRC and does not support IRC. Strong cryptographic
+methods are used to protect SILC packets inside SILC network. Two
+other Internet Drafts relates very closely to this memo; SILC Packet
+Protocol [SILC2] and SILC Key Exchange and Authentication Protocols
+[SILC3].
+
+The protocol uses extensively packets as conferencing protocol
+requires message and command sending. The SILC Packet Protocol is
+described in [SILC2] and should be read to fully comprehend this
+document and protocol. [SILC2] also describes the packet encryption
+and decryption in detail.
+
+The security of SILC protocol and for any security protocol for that
+matter is based on strong and secure key exchange protocol. The SILC
+Key Exchange protocol is described in [SILC3] along with connection
+authentication protocol and should be read to fully comprehend this
+document and protocol.
+
+The SILC protocol has been developed to work on TCP/IP network
+protocol, although it could be made to work on other network protocols
+with only minor changes. However, it is recommended that TCP/IP
+protocol is used under SILC protocol. Typical implementation would
+be made in client-server model.
+
+
+.ti 0
+2. SILC Concepts
+
+This section describes various SILC protocol concepts that forms the
+actual protocol, and in the end, the actual SILC network. The mission
+of the protocol is to deliver messages from clients to other clients
+through routers and servers in secure manner. The messages may also
+be delivered from one client to many clients forming a group, also
+known as a channel.
+
+This section does not focus to security issues, instead basic network
+concepts are introduced to make the topology of the SILC network
+clear.
+
+
+.ti 0
+2.1 SILC Network Topology
+
+SILC network is a cellular network as opposed to tree style network
+topology. The rationale for this is to have servers that can perform
+specific kind of tasks what other servers cannot perform. This leads
+to two kinds of servers; normal SILC servers and SILC routers.
+A difference between normal server and router server is that routers
+knows everything about everything in the network. They also do the
+actual routing of the messages to the correct receiver. Normal servers
+knows only about local information and nothing about global information.
+This makes the network faster as there are less servers that needs to
+keep global information up to date at all time.
+
+This, on the other hand, leads to cellular like network, where routers
+are in the centrum on the cell and servers are connected to the router.
+Following diagram represents SILC network topology.
+
+
+.in 8
+.nf
+ ---- ---- ---- ---- ---- ----
+ | S8 | S5 | S4 | | S7 | S5 | S6 |
+ ----- ---- ----- ----- ---- -----
+| S7 | S/R1 | S2 | --- | S8 | S/R2 | S4 |
+ ---- ------ ---- ---- ------ ----
+ | S6 | S3 | S1 | | S1 | S3 | S2 | ---- ----
+ ---- ---- ---- ---- ---- ---- | S3 | S1 |
+ Cell 1. \\ Cell 2. | \\____ ----- -----
+ | | | S4 | S/R4 |
+ ---- ---- ---- ---- ---- ---- ---- ------
+ | S7 | S4 | S2 | | S1 | S3 | S2 | | S2 | S5 |
+ ----- ---- ----- ----- ---- ----- ---- ----
+ | S6 | S/R3 | S1 | --- | S4 | S/R5 | S5 | Cell 4.
+ ---- ------ ---- ---- ------ ----
+ | S8 | S5 | S3 | | S6 | S7 | S8 | ... etc ...
+ ---- ---- ---- ---- ---- ----
+ Cell 3. Cell 5.
+.in 3
+
+.ce
+Figure 1: SILC Network Topology
+
+
+A cell is formed when a server or servers connect to one router. In
+SILC network normal server cannot directly connect to other normal
+server. Normal server may only connect to SILC router which then
+routes the messages to the other servers in the cell. Router servers
+on the other hand may connect to other routers to form the actual SILC
+network, as seen in above figure. However, router is also normal SILC
+server; clients may connect to it the same way as to normal SILC
+servers. Normal server also cannot have active connections to more
+than one router. Normal server cannot be connected to two different
+cells. Router servers, on the other hand, may have as many router to
+router connections as needed.
+
+There are many issues in this network topology that needs to be careful
+about. Issues like the size of the cells, the number of the routers in
+the SILC network and the capacity requirements of the routers. These
+issues should be discussed in the Internet Community and additional
+documents on the issue will be written.
+
+
+.ti 0
+2.2 Communication Inside a Cell
+
+It is always guaranteed that inside a cell message is delivered to the
+recipient with at most two server hops. Client who is connected to
+server in the cell and is talking on channel to other client connected
+to other server in the same cell, will have its messages delivered from
+its local server first to the router of the cell, and from the router
+to the other server in the cell. Following diagram represents this
+scenario.
+
+
+.in 25
+.nf
+1 --- S1 S4 --- 5
+ S/R
+ 2 -- S2 S3
+ / |
+ 4 3
+.in 3
+
+
+.ce
+Figure 2: Communication Inside cell
+
+
+Example: Client 1. connected to Server 1. message sent to
+ Client 4. connected to Server 2. travels from Server 1.
+ first to Router which routes the message to Server 2.
+ which then sends it to the Client 4. All the other
+ servers in the cell will not see the routed message.
+
+
+If client is connected directly to the router, as router is also normal
+SILC server, the messages inside the cell are always delivered only with
+one server hop. If clients communicating with each other are connected
+to the same server, no router interaction is needed. This is the optimal
+situation of message delivery in the SILC network.
+
+
+.ti 0
+2.3 Communication in the Network
+
+If the message is destined to server that does not belong to local cell
+the message is routed to the router server to which the destination
+server belongs, if the local router is connected to destination router.
+If there is no direct connection to the destination router, the local
+router routes the message to its primary route. Following diagram
+represents message sending between cells.
+
+
+.in 16
+.nf
+1 --- S1 S4 --- 5 S2 --- 1
+ S/R - - - - - - - - S/R
+ 2 -- S2 S3 S1
+ / | \\
+ 4 3 2
+
+ Cell 1. Cell 2.
+.in 3
+
+
+.ce
+Figure 3: Communication Between Cells
+
+
+Example: Client 5. connected to Server 4. in Cell 1. message sent
+ to Client 2. connected to Server 1. in Cell 2. travels
+ from Server 4. to Router which routes the message to
+ Router in Cell 2, which then routes the message to
+ Server 1. All the other servers and routers in the
+ network will not see the routed message.
+
+
+The optimal case of message delivery from client point of view is
+when clients are connected directly to the routers and the messages
+are delivered from one router to the other router.
+
+
+
+
+
+.ti 0
+2.4 Channel Communication
+
+Messages may be sent to group of clients as well. Sending messages to
+many clients works the same way as sending messages point to point, from
+message delivery point of view. Security issues are another matter
+which are not discussed in this section.
+
+Router server handles the message routing to multiple recipients. If
+any recipient is not in the same cell as the sender the messages are
+routed further.
+
+Server distributes the channel message to its local clients who are
+joined to the channel. Also, router distributes the message to its
+local clients on the channel.
+
+
+.ti 0
+3. SILC Specification
+
+This section describes the SILC protocol. However, [SILC2] and
+[SILC3] describes other important protocols that are part of this SILC
+specification and must be read.
+
+
+.ti 0
+3.1 Client
+
+A client is a piece of software connecting to SILC server. SILC client
+cannot be SILC server. Purpose of clients is to provide the user
+interface of the SILC services for end user. Clients are distinguished
+from other clients by unique Client ID. Client ID is a 128 bit ID that
+is used in the communication in the SILC network. The client ID is
+based on the nickname selected by the user. User uses logical nicknames
+in communication which are then mapped to the corresponding Client ID.
+Client ID's are low level identifications and must not be seen by the
+end user.
+
+Clients provide other information about the end user as well. Information
+such as the nickname of the user, username and the hostname of the end
+user and user's real name. See section 3.2 Server for information of
+the requirements of keeping this information.
+
+The nickname selected by the user is not unique in the SILC network.
+There can be 2^8 same nicknames for one IP address. As for comparison to
+IRC [IRC] where nicknames are unique this is a fundamental difference
+between SILC and IRC. This causes the server names to be used along
+with the nicknames to identify specific users when sending messages.
+This feature of SILC makes IRC style nickname-wars obsolete as no one
+owns their nickname; there can always be someone else with the same
+nickname. Another difference is that there are no limit of the length
+of the nickname in the SILC.
+
+
+.ti 0
+3.1.1 Client ID
+
+Client ID is used to identify users in the SILC network. The Client ID
+is unique to the extent that there can be 2^128 different Client ID's.
+Collisions are not expected to happen. The Client ID is defined as
+follows.
+
+.in 6
+128 bit Client ID based on IPv4 addresses:
+
+32 bit ServerID IP address (bits 1-32)
+ 8 bit Random number
+88 bit Truncated MD5 hash value of the nickname
+
+o Server ID IP address - Indicates the server where this
+ client is coming from. The IP address hence equals the
+ server IP address where to the client has connected.
+
+o Random number - Random number to further unify the
+ Client ID. This makes it possible to have 2^8 same
+ nicknames from the same server IP address.
+
+o MD5 hash - MD5 hash value of the nickname is truncated
+ taking 88 bits from the start of the hash value. This
+ hash value is used to search the user's Client ID from
+ the ID lists.
+
+.in 3
+Collisions could occur when more than 2^8 clients using same nickname
+from the same server IP address is connected to the SILC network.
+Server must be able to handle this situation by refusing to accept
+anymore of that nickname.
+
+Another possible collision may happen with the truncated hash value of
+the nickname. It could be possible to have same truncated hash value for
+two different nicknames. However, this is not expected to happen nor
+cause any problems if it would occur. Nicknames are usually logical and
+it is unlikely to have two distinct logical nicknames produce same
+truncated hash value.
+
+
+.ti 0
+3.2 Server
+
+Servers are the most important parts of the SILC network. They form the
+basis of the SILC, providing a point to which clients may connect to.
+There are two kinds of servers in SILC; normal servers and router servers.
+This section focuses on the normal server and router server is described
+in the section 3.3 Router.
+
+Normal servers may not directly connect to other normal server. Normal
+servers may only directly connect to router server. If the message sent
+by the client is destined outside the local server it is always sent to
+the router server for further routing. Server may only have one active
+connection to router on same port. Normal server may not connect to other
+cell's router except in situations where its cell's router is unavailable.
+
+Servers and routers in the SILC network are considered to be trusted.
+With out a doubt, servers that are set to work on ports above 1023 are
+not considered to be trusted. Also, the service provider acts important
+role in the server's trustworthy.
+
+
+.ti 0
+3.2.1 Server's Local ID List
+
+Normal server keeps various information about the clients and their end
+users connected to it. Every normal server must keep list of all locally
+connected clients, Client ID's, nicknames, usernames and hostnames and
+user's real name. Normal servers only keeps local information and it
+does not keep any global information. Hence, normal servers knows only
+about their locally connected clients. This makes servers efficient as
+they don't have to worry about global clients. Server is also responsible
+of creating the Client ID's for their clients.
+
+Normal server also keeps information about locally created channels and
+their Channel ID's.
+
+Hence, local list for normal server includes:
+
+.in 6
+server list - Router connection
+ o Server name
+ o Server IP address
+ o Server ID
+ o Sending key
+ o Receiving key
+ o Public key
+
+client list - All clients in server
+ o Nickname
+ o Username@host
+ o Real name
+ o Client ID
+ o Sending key
+ o Receiving key
+
+
+
+channel list - All channels in server
+ o Channel name
+ o Channel ID
+ o Client ID's on channel
+ o Client ID modes on channel
+ o Channel key
+.in 3
+
+
+
+.ti 0
+3.2.2 Server ID
+
+Servers are distinguished from other servers by unique 64 bit Server ID.
+The Server ID is used in the SILC to route messages to correct servers.
+Server ID's also provide information for Client ID's, see section 3.1.1
+Client ID. Server ID is defined as follows.
+
+.in 6
+64 bit Server ID based on IPv4 addresses:
+
+32 bit IP address of the server
+16 bit Port
+16 bit Random number
+
+o IP address of the server - This is the real IP address of
+ the server.
+
+o Port - This is the port the server is binded to.
+
+o Random number - This is used to further unify the Server ID.
+
+.in 3
+Collisions are not expected to happen in any conditions. The Server ID
+is always created by the server itself and server is resposible of
+distributing it to the router.
+
+
+.ti 0
+3.2.3 SILC Server Ports
+
+SILC uses currently TCP port 334 on SILC network. However, this is not
+official port assigned for SILC. Official port has been requested by
+the IANA.
+
+If there are needs to create new SILC networks in the future the port
+numbers must be officially assigned by the IANA. Most convenience case
+would be to assign port numbers upwards from 334.
+
+Server on network above privileged ports (>1023) should not be trusted
+as they could have been set up by untrusted party.
+
+
+.ti 0
+3.3 Router
+
+Router server in SILC network is responsible for keeping the cell together
+and routing messages to other servers and to other routers. Router server
+is also a normal server thus clients may connect to it as it would be
+just normal SILC server.
+
+However, router servers has a lot of important tasks that normal servers
+do not have. Router server knows everything about everything in the SILC.
+They know all clients currently on SILC, all servers and routers and all
+channels in SILC. Routers are the only servers in SILC that care about
+global information and keeping them up to date at all time. And, this
+is what they must do.
+
+
+.ti 0
+3.3.1 Router's Local ID List
+
+Router server as well must keep local list of connected clients and
+locally created channels. However, this list is extended to include all
+the informations of the entire cell, not just the server itself as for
+normal servers.
+
+However, on router this list is a lot smaller since routers do not keep
+information about user's nickname, username and hostname and real name
+since these are not needed by the router. Router keeps only information
+that it needs.
+
+Hence, local list for router includes:
+
+.in 6
+server list - All servers in the cell
+ o Server name
+ o Server ID
+ o Router's Server ID
+ o Sending key
+ o Receiving key
+
+client list - All clients in the cell
+ o Client ID
+
+channel list - All channels in the cell
+ o Channel ID
+ o Client ID's on channel
+ o Client ID modes on channel
+ o Channel key
+.in 3
+
+
+Note that locally connected clients and other information include all the
+same information as defined in section section 3.2.1 Server's Local ID
+List.
+
+
+.ti 0
+3.3.2 Router's Global ID List
+
+Router server must also keep global list. Normal servers do not have
+global list as they know only about local information. Global list
+includes all the clients on SILC, their Client ID's, all created channels
+and their Channel ID's and all servers and routers on SILC and their
+Server ID's. That is said, global list is for global information and the
+list must not include the local information already on the router's local
+list.
+
+Note that the global list does not include information like nicknames,
+usernames and hostnames or user's real names. Router does not keep
+these informations as they are not needed by the router. This
+information is available from the client's server which maybe queried
+when needed.
+
+Hence, global list includes:
+
+.in 6
+server list - All servers in SILC
+ o Server name
+ o Server ID
+ o Router's Server ID
+
+client list - All clients in SILC
+ o Client ID
+
+channel list - All channels in SILC
+ o Channel ID
+ o Client ID's on channel
+ o Client ID modes on channel
+.in 3
+
+
+.ti 0
+3.3.3 Router's Server ID
+
+Router's Server ID's are equivalent to normal Server ID's. As routers
+are normal servers as well same types of ID's applies for routers as well.
+Thus, see section 3.2.2 Server ID. Server ID's for routers are always
+created by the remote router where the router is connected to.
+
+
+.ti 0
+3.4 Channels
+
+A channel is a named group of one or more clients which will all receive
+messages addressed to that channel. The channel is created when first
+client requests JOIN command to the channel, and the channel ceases to
+exist when the last client leaves it. When channel exists, any client
+can reference it using the name of the channel.
+
+Channel names are unique although the real uniqueness comes from 64 bit
+Channel ID that unifies each channel. However, channel names are still
+unique and no two global channels with same name may exist. Channel name
+is a string which begins with `#' character. There is no limit on the
+length of the channel name. Channel names may not contain any spaces
+(` '), any non-printable ASCII characters, commas (`,') and wildcard
+characters.
+
+Channels can have operators that can administrate the channel and
+operate all of its modes. Following operators on channel exist on SILC
+network.
+
+.in 6
+o Channel founder - When channel is created the joining client becomes
+ channel founder. Channel founder is channel operator with some more
+ privileges. Basically, channel founder can fully operate the channel
+ and all of its modes. The privileges are limited only to the particular
+ channel. There can be only one channel founder per channel. Channel
+ founder supersedes channel operator's privileges.
+
+ Channel founder privileges cannot be removed by any other operator on
+ channel. When channel founder leaves the channel there is no channel
+ founder on the channel. Channel founder also cannot be removed by
+ force from the channel.
+
+o Channel operator - When client joins to channel that has not existed
+ previously it will become automatically channel operator (and channel
+ founder discussed above). Channel operator is able administrate the
+ channel, set some modes on channel, remove a badly behaving client from
+ the channel and promote other clients to become channel operator.
+ The privileges are limited only to the particular channel.
+
+ Normal channel user may be promoted (opped) to channel operator
+ gaining channel operator privileges. Channel founder or other channel
+ operator may also demote (deop) channel operator to normal channel
+ user.
+.in 3
+
+
+.ti 0
+3.4.1 Channel ID
+
+Channels are distinguished from other channels by unique Channel ID.
+The Channel ID is a 64 bit ID and collisions are not expected to happen
+in any conditions. Channel names are just for logical use of channels.
+The Channel ID is created by the server where the channel is created.
+The Channel ID is defined as follows.
+
+.in 6
+64 bit Channel ID based on IPv4 addresses:
+
+32 bit Router's Server ID IP address (bits 1-32)
+16 bit Router's Server ID port (bits 33-48)
+16 bit Random number
+
+o Router's Server ID IP address - Indicates the IP address of
+ the router of the cell where this channel is created. This is
+ taken from the router's Server ID. This way SILC router knows
+ where this channel resides in the SILC network.
+
+o Router's Server ID port - Indicates the port of the channel on
+ the server. This is taken from the router's Server ID.
+
+o Random number - To further unify the Channel ID. This makes
+ sure that there are no collisions. This also means that
+ in a cell there can be 2^16 channels.
+.in 3
+
+
+.ti 0
+3.5 Operators
+
+Operators are normal users with extra privileges to their server or
+router. Usually these people are SILC server and router administrators
+that take care of their own server and clients on them. The purpose of
+operators is to administrate the SILC server or router. However, even
+an operator with highest privileges is not able to enter invite-only
+channel, to gain access to the contents of a encrypted and authenticated
+packets traveling in the SILC network or to gain channel operator
+privileges on public channels without being promoted. They have the
+same privileges as everyone else except they are able to administrate
+their server or router.
+
+
+.ti 0
+3.6 SILC Commands
+
+Commands are very important part on SILC network especially for client
+which uses commands to operate on the SILC network. Commands are used
+to set nickname, join to channel, change modes and many other things.
+
+Client usually sends the commands and server replies by sending a reply
+packet to the command. Server may also send commands usually to serve
+the original client's request. However, server may not send command
+to client and there are some commands that server must not send.
+
+Note that the command reply is usually sent only after client has sent
+the command request but server is allowed to send command reply packet
+to client even if client has not requested the command. Client may,
+however, choose not to accept the command reply, but there are some
+command replies that the client should accept. Example of a such
+command reply is reply to SILC_COMMAND_CMODE command that the server
+uses to distribute the channel mode on all clients on the channel
+when the mode has changed.
+
+It is expected that some of the commands may be miss-used by clients
+resulting various problems on the server side. Every implementation
+should assure that commands may not be executed more than once, say,
+in two (2) seconds. This should be sufficient to prevent the miss-use
+of commands.
+
+SILC commands are described in section 5 SILC Commands.
+
+
+.ti 0
+3.7 SILC Packets
+
+Packets are naturally the most important part of the protocol and the
+packets are what actually makes the protocol. Packets in SILC network
+are always encrypted using, usually, the shared secret session key
+or some other key, for example, channel key, when encrypting channel
+messages. The SILC Packet Protocol is a wide protocol and is described
+in [SILC2]. This document does not define or describe details of
+SILC packets.
+
+
+.ti 0
+3.8 Packet Encryption
+
+All packets passed in SILC network must be encrypted. This section
+defines how packets must be encrypted in the SILC network. The detailed
+description of the actual encryption process of the packets are
+described in [SILC2].
+
+Client and its server shares secret symmetric session key which is
+established by the SILC Key Exchange Protocol, described in [SILC3].
+Every packet sent from client to server, with exception of packets for
+channels, are encrypted with this session key.
+
+Channels has their own key that are shared by every client on the channel.
+However, the channel keys are cell specific thus one cell does not know
+the channel key of the other cell, even if that key is for same channel.
+Channel key is also known by the routers and all servers that has clients
+on the channel. However, channels may have channel private keys that
+are entirely local setting for client. All clients on the channel must
+know the channel private key before hand to be able to talk on the
+channel. In this case, no server or router knows the key for channel.
+
+Server shares secret symmetric session key with router which is
+established by the SILC Key Exchange Protocol. Every packet passed from
+server to router, with exception of packets for channels, are encrypted
+with the shared session key. Same way, router server shares secret
+symmetric key with its primary route. However, every packet passed
+from router to other router, including packets for channels, are
+encrypted with the shared session key. Every router connection has
+their own session keys.
+
+
+.ti 0
+3.8.1 Determination of the Source and the Destination
+
+The source and the destination of the packet needs to be determined
+to be able to route the packets to correct receiver. This information
+is available in the SILC Packet Header which is included in all packets
+sent in SILC network. The SILC Packet Header is described in [SILC2].
+
+The header is always encrypted with the session key who is next receiver
+of the packet along the route. The receiver of the packet, for example
+a router along the route, is able to determine the sender and the
+destination of the packet by decrypting the SILC Packet Header and
+checking the ID's attached to the header. The ID's in the header will
+tell to where the packet needs to be sent and where it is coming from.
+
+The header in the packet does not change during the routing of the
+packet. The original sender, for example client, assembles the packet
+and the packet header and server or router between the sender and the
+receiver must not change the packet header.
+
+Note that the packet and the packet header may be encrypted with
+different keys. For example, packets to channels are encrypted with
+the channel key, however, the header is encrypted with the session key
+as described above. However, the header and the packet may be encrypted
+with same key. This is case, for example, with command packets.
+
+
+.ti 0
+3.8.2 Client To Client
+
+Process of message delivery and encryption from client to another
+client is as follows.
+
+Example: Private message from client to another client on different
+ servers. Clients do not share private message delivery
+ keys; normal session keys are used.
+
+o Client 1. sends encrypted packet to its server. The packet is
+ encrypted with the session key shared between client and its
+ server.
+
+o Server determines the destination of the packet and decrypts
+ the packet. Server encrypts the packet with session key shared
+ between the server and its router, and sends the packet to the
+ router.
+
+o Router determines the destination of the packet and decrypts
+ the packet. Router encrypts the packet with session key
+ shared between the router and the destination server, and sends
+ the packet to the server.
+
+o Server determines the client to which the packet is destined
+ to and decrypts the packet. Server encrypts the packet with
+ session key shared between the server and the destination client,
+ and sends the packet to the client.
+
+o Client 2. decrypts the packet.
+
+
+Example: Private message from client to another client on different
+ servers. Clients has established secret shared private
+ message delivery key with each other and that is used in
+ the message encryption.
+
+o Client 1. sends encrypted packet to its server. The packet is
+ encrypted with the private message delivery key shared between
+ clients.
+
+o Server determines the destination of the packet and sends the
+ packet to the router.
+
+o Router determines the destination of the packet and sends the
+ packet to the server.
+
+o Server determines the client to which the packet is destined
+ to and sends the packet to the client.
+
+o Client 2. decrypts the packet with the secret shared key.
+
+
+If clients share secret key with each other the private message
+delivery is much simpler since servers and routers between the
+clients do not need to decrypt and re-encrypt the packet.
+
+The process for clients on same server is much simpler as there are
+no need to send the packet to the router. The process for clients
+on different cells is same as above except that the packet is routed
+outside the cell. The router of the destination cell routes the
+packet to the destination same way as described above.
+
+
+.ti 0
+3.8.3 Client To Channel
+
+Process of message delivery from client on channel to all the clients
+on the channel.
+
+Example: Channel of four users; two on same server, other two on
+ different cells. Client sends message to the channel.
+
+o Client 1. encrypts the packet with channel key and sends the
+ packet to its server.
+
+o Server determines local clients on the channel and sends the
+ packet to the Client on the same server. Server then sends
+ the packet to its router for further routing.
+
+o Router determines local clients on the channel, if found
+ sends packet to the local clients. Router determines global
+ clients on the channel and sends the packet to its primary
+ router or fastest route.
+
+o (Other router(s) do the same thing and sends the packet to
+ the server(s))
+
+o Server determines local clients on the channel and sends the
+ packet to the client.
+
+o All clients receiving the packet decrypts the packet.
+
+
+.ti 0
+3.8.4 Server To Server
+
+Server to server packet delivery and encryption is described in above
+examples. Router to router packet delivery is analogous to server to
+server. However, some packets, such as channel packets, are processed
+differently. These cases are described later in this document and
+more in detail in [SILC2].
+
+
+.ti 0
+3.9 Key Exchange And Authentication
+
+Key exchange is done always when for example client connects to server
+but also when server and router and router and router connects to each
+other. The purpose of key exchange protocol is to provide secure key
+material to be used in the communication. The key material is used to
+derive various security parameters used to secure SILC packets. The
+SILC Key Exchange protocol is described in detail in [SILC3].
+
+Authentication is done after key exchange protocol has been successfully
+completed. The purpose of authentication is to authenticate for example
+client connecting to the server. However, Usually clients are accepted
+to connect to server without explicit authentication. Servers are
+required use authentication protocol when connecting. The authentication
+may be based on passphrase (pre-shared-secret) or public key. The
+connection authentication protocol is described in detail in [SILC3].
+
+
+.ti 0
+3.10 Algorithms
+
+This section defines all the allowed algorithms that can be used in
+the SILC protocol. This includes mandatory cipher, mandatory public
+key algorithm and MAC algorithms.
+
+
+.ti 0
+3.10.1 Ciphers
+
+Cipher is the encryption algorithm that is used to protect the data
+in the SILC packets. See [SILC2] of the actual encryption process and
+definition of how it must be done. SILC has a mandatory algorithm that
+must be supported in order to be compliant with this protocol.
+
+Following ciphers are defined in SILC protocol:
+
+.in 6
+blowfish-cbc Blowfish in CBC mode (mandatory)
+twofish-cbc Twofish in CBC mode (optional)
+rc6-cbc RC6 in CBC mode (optional)
+rc5-cbc RC5 in CBC mode (optional)
+mars-cbc Mars in CBC mode (optional)
+none No encryption (optional)
+.in 3
+
+
+All algorithms must use minimum of 128 bit key, by default. Several
+algorithms, however, supports longer keys and it is recommended to use
+longer keys if they are available.
+
+Algorithm none does not perform any encryption process at all and
+thus is not recommended to be used. It is recommended that no client
+or server implementation would accept none algorithms except in special
+debugging mode.
+
+Additional ciphers may be defined to be used in SILC by using the
+same name format as above.
+
+
+
+
+
+
+.ti 0
+3.10.2 Public Key Algorithms
+
+Public keys are used in SILC to authenticate entities in SILC network
+and to perform other tasks related to public key cryptography. The
+public keys are also used in the SILC Key Exchange protocol [SILC3].
+
+Following public key algorithms are defined in SILC protocol:
+
+.in 6
+rsa RSA (mandatory)
+dss DSS (optional)
+.in 3
+
+Both of the algorithms are described in [Scheneir] and [Menezes].
+
+Additional public key algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.10.3 MAC Algorithms
+
+Data integrity is protected by computing a message authentication code
+(MAC) of the packet data. See [SILC2] for details how to compute the
+MAC.
+
+Following MAC algorithms are defined in SILC protocol:
+
+.in 6
+hmac-sha1 HMAC-SHA1, length = 20 (mandatory)
+hmac-md5 HMAC-MD5, length = 16 (optional)
+none No MAC (optional)
+.in 3
+
+The none MAC is not recommended to be used as the packet is not
+authenticated when MAC is not computed. It is recommended that no
+client or server would accept none MAC except in special debugging
+mode.
+
+The HMAC algorithm is described in [HMAC] and hash algorithms that
+are used as part of the HMACs are described in [Scheneir] and in
+[Menezes]
+
+Additional MAC algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.10.4 Compression Algorithms
+
+SILC protocol supports compression that may be applied to unencrypted
+data. It is recommended to use compression on slow links as it may
+significantly speed up the data transmission. By default, SILC does not
+use compression which is the mode that must be supported by all SILC
+implementations.
+
+Following compression algorithms are defined:
+
+.in 6
+none No compression (mandatory)
+zlib GBU ZLIB (LZ77) compression (optional)
+.in 3
+
+Additional compression algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.11 SILC Public Key
+
+This section defines the type and format of the SILC public key. All
+implementations must support this public key type. See [SILC3] for
+other optional public key and certificate types allowed in SILC
+protocol. Public keys in SILC may be used to authenticate entities
+and to perform other tasks related to public key cryptography.
+
+The format of the SILC Public Key is as follows:
+
+
+.in 5
+.nf
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Public Key Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Algorithm Name Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Algorithm Name ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Identifier Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ Identifier ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Public Data ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 4: SILC Public Key
+
+
+.in 6
+o Public Key Length (4 bytes) - Indicates the full length
+ of the public key, not including this field.
+
+o Algorithm Name Length (2 bytes) - Indicates the length
+ of the Algorithm Length field, not including this field.
+
+o Algorithm name (variable length) - Indicates the name
+ of the public key algorithm that the key is. See the
+ section 3.10.2 Public Key Algorithms for defined names.
+
+o Identifier Length (2 bytes) - Indicates the length of
+ the Identifier field, not including this field.
+
+o Identifier (variable length) - Indicates the identifier
+ of the public key. This data can be used to identify
+ the owner of the key. The identifier is of following
+ format:
+
+ UN User name
+ HN Host name or IP address
+ RN Real name
+ E EMail address
+ O Organization
+ C Country
+
+
+ Examples of an identifier:
+
+ `UN=priikone, HN=poseidon.pspt.fi, E=priikone@poseidon.pspt.fi'
+
+ `UN=sam, HN=dummy.fi, RN=Sammy Sam, O=Company XYZ, C=Finland'
+
+ At least user name (UN) and host name (HN) must be provided as
+ identifier. The fields are separated by commas (`,'). If
+ comma is in the identifier string it must be written as `\\,',
+ for example, `O=Company XYZ\\, Inc.'.
+
+o Public Data (variable length) - Includes the actual
+ public data of the public key.
+
+ The format of this field for RSA algorithm is
+ as follows:
+
+ 4 bytes Length of e
+ variable length e
+ 4 bytes Length of n
+ variable length n
+
+
+ The format of this field for DSS algorithm is
+ as follows:
+
+ 4 bytes Length of p
+ variable length p
+ 4 bytes Length of q
+ variable length q
+ 4 bytes Length of g
+ variable length g
+ 4 bytes Length of y
+ variable length y
+
+ The variable length fields are multiple precession
+ integers encoded as strings in both examples.
+
+ Other algorithms must define their own type of this
+ field if they are used.
+.in 3
+
+All fields in the public key are in MSB (most significant byte first)
+order.
+
+
+.ti 0
+4 SILC Procedures
+
+This section describes various SILC procedures such as how the
+connections are created and registered, how channels are created and
+so on. The section describes the procedures only generally as details
+are described in [SILC2] and [SILC3].
+
+
+.ti 0
+4.1 Creating Client Connection
+
+This section descibres the procedure when client connects to SILC server.
+When client connects to server the server must perform IP address lookup
+and reverse IP address lookup to assure that the origin host really is
+who it claims to be. Client, host, connecting to server must have
+both valid IP address and fully qualified domain name (FQDN).
+
+After that client and server performs SILC Key Exchange protocol which
+will provide the key material used later in the communication. The
+key exchange protocol must be completed successfully before the connection
+registration may continue. The SILC Key Exchange protocol is described
+in [SILC3].
+
+Typical server implementation would keep a list of connections that it
+allows to connect to the server. The implementation would check, for
+example, the connecting client's IP address from the connection list
+before the SILC Key Exchange protocol has been started. Reason for
+this is that if the host is not allowed to connect to the server there
+is no reason to perform a key exchange protocol.
+
+After successful key exchange protocol the client and server performs
+connection authentication protocol. The purpose of the protocol is to
+authenticate the client connecting to the server. Flexible
+implementation could also accept the client to connect to the server
+without explicit authentication. However, if authentication is
+desired for a specific client it may be based on passphrase or
+public key authentication. If authentication fails the connection
+must be terminated. The connection authentication protocol is described
+in [SILC3].
+
+After successful key exchange and authentication protocol the client
+registers itself by sending SILC_PACKET_NEW_CLIENT packet to the
+server. This packet includes various information about the client
+that the server uses to create the client. Server creates the client
+and sends SILC_PACKET_NEW_ID to the client which includes the created
+Client ID that the client must start using after that. After that
+all SILC packets from the client must have the Client ID as the
+Source ID in the SILC Packet Header, described in [SILC2].
+
+Client must also get the server's Server ID that is to be used as
+Destination ID in the SILC Packet Header when communicating with
+the server (for example when sending commands to the server). The
+ID may be resolved in two ways. Client can take the ID from an
+previously received packet from server that must include the ID,
+or to send SILC_COMMAND_INFO command and receive the Server ID as
+command reply.
+
+Server may choose not to use the information received in the
+SILC_PACKET_NEW_CLIENT packet. For example, if public key or
+certificate were used in the authentication, server may use those
+informations rather than what it received from client. This is suitable
+way to get the true information about client if it is available.
+
+The nickname of client is initially set to the username sent in the
+SILC_PACKET_NEW_CLIENT packet. User should set the nickname to more
+suitable by sending SILC_COMMAND_NICK command. However, this is not
+required as part of registration process.
+
+Server must also distribute the information about newly registered
+client to its router (or if the server is router, to all routers in
+the SILC network). More information about this in [SILC2].
+
+
+.ti 0
+4.2 Creating Server Connection
+
+This section descibres the procedure when server connects to its
+router (or when router connects to other router, the cases are
+equivalent). The procedure is very much alike when client connects
+to the server thus it is not repeated here.
+
+One difference is that server must perform connection authentication
+protocol with proper authentication. Proper authentication is based
+on passphrase or public key authentication.
+
+After server and router has successfully performed the key exchange
+and connection authentication protocol, the server register itself
+to the router by sending SILC_PACKET_NEW_SERVER packet. This packet
+includes the server's Server ID that it has created by itself and
+other relevant information about the server.
+
+After router has received the SILC_PACKET_NEW_SERVER packet it
+distributes the information about newly registered server to all routers
+in the SILC network. More information about this in [SILC2].
+
+As client needed to resolve the destination ID this must be done by the
+server that connected to the router, as well. The way to resolve it is
+to get the ID from previously received packet. Server must also start
+using its own Server ID as Source ID in SILC Packet Header and the
+router's Server ID as Destination when communicating with the router.
+
+If the server has already connected clients and locally created
+channels the server must distribute these informations to the router.
+The distribution is done by sending packet SILC_PACKET_NEW_CHANNEL.
+See [SILC2] for more information on this.
+
+
+.ti 0
+4.3 Joining to a Channel
+
+This section describes the procedure when client joins to a channel.
+Client may join to channel by sending command SILC_COMMAND_JOIN to the
+server. If the receiver receiving join command is normal server the
+server must check its local list whether this channel already exists
+locally. This would indicate that some client connected to the server
+has already joined to the channel. If this is case the client is
+joined to the client, new channel key is created and information about
+newly joined channel is sent to the router. The new channel key is
+also distributed to the router and to all clients on the channel.
+
+If the channel does not exist in the local list the command must be
+sent to the router which will then perform the actual joining
+procedure. When server receives the reply to the command from the
+router it must be distributed to the client who sent the command
+originally. Server will also receive the channel key from the server
+that it must distribute to the client who originally requested the
+join command. The server must also save the channel key.
+
+If the receiver of the join command is router it must first check its
+local list whether anyone in the cell has already joined to the channel.
+If this is the case the client is joined to the channel and reply is
+sent to the client. If the command was sent by server the command reply
+is sent to the server who sent it. Then the router must also create
+new channel key and distribute it to all clients on the channel and
+all servers that has clients on the channel.
+
+If the channel does not exist on the router's local list it must
+check the global list whether the channel exists at all. If it does
+the client is joined to the channel as described previously. If
+the channel does not exist the channel is created and the client
+is joined to the channel. The channel key is also created and
+distributed as previously described. The client joining to the created
+channel is made automatically channel founder and both channel founder
+and channel operator privileges is set for the client.
+
+When the router joins the client to the channel it must send
+information about newly joined client to all routers in the SILC
+network. Also, if the channel was created in the process, information
+about newly created channel must also be distributed to all routers.
+The distribution of newly created channel is done by sending packet
+SILC_PACKET_NEW_CHANNEL.
+
+It is important to note that new channel key is created always when
+new client joins to channel, whether the channel has existed previously
+or not. This way the new client on the channel is not able to decrypt
+any of the old traffic on the channel.
+
+Client who receives the reply to the join command must start using
+the received Channel ID in the channel message communication thereafter.
+However, client must not start communicating on the channel before
+it has received the packet SILC_PACKET_CHANNEL_KEY.
+
+If client wants to know the other clients currently on the channel
+the client must send SILC_COMMAND_NAMES command to receive a list of
+channel users. Server implementation, however, may send command reply
+packet to SILC_COMMAND_NAMES command after client has joined to the
+channel even if the client has not sent the command.
+
+
+.ti 0
+4.4 Channel Key Generation
+
+Channel keys are created by router who creates the channel by taking
+enough randomness from cryptographically strong random number generator.
+The key is generated always when channel is created, when new client
+joins a channel and after the key has expired. Key could expire for
+example in an hour.
+
+The key must also be re-generated whenever some client leaves a channel.
+In this case the key is created from scratch by taking enough randomness
+from the random number generator. After that the key is distributed to
+all clients on the channel. However, channel keys are cell specific thus
+the key is created only on the cell where the client, who leaved the
+channel, exists. While the server or router is creating the new channel
+key, no other client may join to the channel. Messages that are sent
+while creating the new key are still processed with the old key. After
+server has sent the SILC_PACKET_CHANNEL_KEY packet must client start
+using the new key. If server creates the new key the server must also
+send the new key to its router. See [SILC2] on more information about
+how channel messages must be encrypted and decrypted when router is
+processing them.
+
+
+.ti 0
+4.5 Private Message Sending and Reception
+
+Private messages are sent point to point. Client explicitly destines
+a private message to specific client that is delivered to only to that
+client. No other client may receive the private message. The receiver
+of the private message is destined in the SILC Packet Header as any
+other packet as well.
+
+If the sender of a private message does not know the receiver's Client
+ID, it must resolve it from server. There are two ways to resolve the
+client ID from server; it is recommended that client ipmlementations
+send SILC_COMMAND_IDENTIFY command to receive the Client ID. Client
+may also send SILC_COMMAND_WHOIS command to receive the Client ID.
+If the sender has received earlier a private message from the receiver
+it should have cached the Client ID from the SILC Packet Header.
+
+Receiver of a private message should not explicitly trust the nickname
+that it receives in the Private Message Payload, described in [SILC2].
+Implementations could resolve the nickname from server, as described
+previously, and compare the received Client ID and the SILC Packet
+Header's Client ID. The nickname in the payload is merely provided
+to be displayed for end user.
+
+See [SILC2] for describtion of private message encryption and decryption
+process.
+
+
+.ti 0
+4.6 Private Message Key Generation
+
+Private message may be protected by key generated by client. The key
+may be generated and sent to the other client by sending packet
+SILC_PACKET_PRIVATE_MESSAGE_KEY which travels through the network
+and is secured by session keys. After that the private message key
+is used in the private message communication between those clients.
+See more information about how this works technically in [SILC2].
+
+Other choice is to entirely use keys that are not sent through
+the SILC network at all. This significantly adds security. This key
+would be pre-shared-key that is known by both of the clients. Both
+agree about using the key and starts sending packets that indicate
+that the private message is secured using private message key. This
+is the technical aspect mentioned previously that is described
+in [SILC2].
+
+If the private message keys are not set to be used, which is the
+case by default in SILC, the private messages are secured by using
+normal session keys established by SILC Key Exchange protocol.
+
+
+.ti 0
+4.7 Channel Message Sending and Reception
+
+Channel messages are delivered to group of users. The group forms a
+channel and all clients on the channel receives messages sent to the
+channel.
+
+Channel messages are destined to channel by specifying the Channel ID
+as Destination ID in the SILC Packet Header. The server must then
+distribute the message to all clients on the channel by sending the
+channel message destined explicitly to a client on the channel.
+
+See [SILC2] for describtion of channel message encryption and decryption
+process.
+
+
+.ti 0
+4.8 Session Key Regeneration
+
+Session keys should be regenerated peridiocally, say, once in an hour.
+The re-key process is started by sending SILC_PACKET_REKEY packet to
+other end, to indicate that re-key must be performed.
+
+If perfect forward secrecy (PFS) flag was selected in the SILC Key
+Exchange protocol [SILC3] the re-key must cause new key exchange with
+SKE protocol. In this case the protocol is secured with the old key
+and the protocol results to new key material. See [SILC3] for more
+information. After the SILC_PACKET_REKEY packet is sent the sender
+will perform the SKE protocol.
+
+If PFS flag was not set, which is the default case, then re-key is done
+without executing SKE protocol. In this case, the new key is created by
+hashing the old key with hash function selected earlier in the SKE
+protocol. If the digest length of the hash function is too short for the
+key, then the key is distributed as described in section Processing the
+Key Material in [SILC3]. After both parties has regenerated the session
+key, both send SILC_PACKET_REKEY_DONE packet to each other. These packets
+are still secured with the old key. After these packets, following
+packets must be protected with the new key.
+
+
+.ti 0
+4.9 Command Sending and Reception
+
+Client usually sends the commands in the SILC network. In this case
+the client simply sends the command packet to server and the server
+processes it and replies with command reply packet.
+
+However, if the server is not able to process the command, it is usually
+sent to the server's router. This is case for example with commands such
+as, SILC_COMMAND_JOIN and SILC_COMMAND_WHOIS commands. However, there
+are other commands as well. For example, if client sends the WHOIS
+command requesting specific information about some client the server must
+send the WHOIS command to router so that all clients in SILC network
+are searched. The router, on the other hand, sends the WHOIS command
+to further to receive the exact information about the requested client.
+The WHOIS command travels all the way to the server who owns the client
+and it replies with command reply packet. Finally, the server who
+sent the command receives the command reply and it must be able to
+determine which client sent the original command. The server then
+sends command reply to the client. Implementations should have some
+kind of cache to handle, for example, WHOIS information. Servers
+and routers along the route could all cache the information for faster
+referencing in the future.
+
+The commands sent by server may be sent hop by hop until someone is able
+to process the command. However, it is preferred to destine the command
+as precisely as it is possible. In this case, other routers en route
+must route the command packet by checking the true sender and true
+destination of the packet. However, servers and routers must not route
+command reply packets to clients coming from other server. Client
+must not accept command reply packet originated from anyone else but
+from its own server.
+
+
+.ti 0
+5 SILC Commands
+
+.ti 0
+5.1 SILC Commands Syntax
+
+This section briefly describes the syntax of the command notions
+in this document. Every field in command is separated from each
+other by whitespaces (` ') indicating that each field is independent
+argument and each argument must have own Command Argument Payload.
+The number of maximum arguments are defined with each command
+separately. The Command Argument Payload is described in [SILC2].
+
+Every command defines specific number for each argument. Currently,
+they are defined in ascending order; first argument has number one
+(1), second has number two (2) and so on. This number is set into the
+Argument Type field in the Command Argument Payload. This makes it
+possible to send the arguments in free order as the number must be
+used to identify the type of the argument. This makes is it also
+possible to have multiple optional arguments in commands and in
+command replies. The number of argument is marked in parentheses
+before the actual argument.
+
+.in 6
+Example: Arguments: (1) <nickname> (2) <username@host>
+.in 3
+
+
+Every command replies with Status Payload. This payload tells the
+sender of the command whether the command was completed succefully or
+whether there was an error. If error occured the payload includes the
+error type. In the next section the Status Payload is not described
+as it is common to all commands and has been described here. Commands
+may reply with other arguments as well. These arguments are command
+specific and are described in the next section.
+
+Example command:
+.in 6
+
+EXAMPLE_COMMAND
+
+.in 8
+Max Arguments: 3
+ Arguments: (1) <nickname>[@<server>] (2) <message>
+ (3) [<count>]
+
+The command has maximum of 3 arguments. However, only first
+and second arguments are mandatory.
+
+First argument <nickname> is mandatory but may have optional
+<nickname@server> format as well. Second argument is mandatory
+<message> argument. Third argument is optional <count> argument.
+
+The numbers in parentheses are the argument specific numbers
+that specify the type of the argument in Command Argument Payload.
+The receiver always knows that, say, argument number two (2) is
+<message> argument, regardles of the ordering of the arguments in
+the Command Payload.
+
+Reply messages to the command:
+
+Max Arguments: 4
+ Arguments: (1) <Status Payload> (2) [<channel list>]
+ (3) <idle time> (4) [<away message>]
+
+This command may reply with maximum of 4 arguments. However,
+only the first and third arguments are mandatory. The numbers
+in the parentheses have the same meaning as in the upper
+command sending specification.
+
+Every command reply with <Status Payload>, it is mandatory
+argument for all command replies and for this reason it is not
+described in the command reply descriptions.
+
+Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_TOO_MANY_TARGETS
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_NICK
+
+Every command reply also defines set of status message that it
+may return inside the <Status Payload>. All status messages
+are defined in the section 5.3 SILC Command Status Types.
+.in 3
+
+
+.ti 0
+5.2 SILC Commands List
+
+This section lists all SILC commands, however, it is expected that a
+implementation and especially client implementation has many more
+commands that has only local affect. These commands are official
+SILC commands that has both client and server sides and cannot be
+characterized as local commands.
+
+List of all defined commands in SILC follows.
+
+.in 0
+ 0 SILC_COMMAND_NONE
+
+ None. This is reserved command and must not be sent.
+
+
+ 2 SILC_COMMAND_WHOIS
+
+ Max Arguments: 2
+ Arguments: (1) <nickname>[@<server>] (2) [<count>]
+
+ Whois. Whois command is used to query various information about
+ specific user. The user maybe requested by their nickname and
+ server name. The query may find multiple matching users as
+ there are no unique nicknames in the SILC. The <count> option
+ maybe given to narrow down the number of accepted results. If
+ this is not defined there are no limit of accepted results.
+ The query may also be narrowed down by defining the server name
+ of the nickname.
+
+ To prevent miss-use of this service wildcards in the nickname
+ or in the servername are not permitted. It is not allowed
+ to request all users on some server. The WHOIS requests must
+ be based on specific nickname request.
+
+ The WHOIS request must be always forwarded to router by server
+ so that all users are searched. However, the server still must
+ search its locally connected clients. The server must send
+ this command to the server who owns the requested client. That
+ server must reply to the command.
+
+ Reply messages to the command:
+
+ Max Arguments: 7
+ Arguments: (1) <Status Payload> (2) <Client ID>
+ (3) <nickname>[@<server>] (4) <username@host>
+ (5) <real name> (6) [<channel list>]
+ (7) [<idle time>]
+
+ This command may reply with several command reply messages to
+ form a list of results. In this case the status payload will
+ include STATUS_LIST_START status in the first reply and
+ STATUS_LIST_END in the last reply to indicate the end of the
+ list. If there are only one reply the status is set to normal
+ STATUS_OK.
+
+ The command replies include the Client ID of the nickname,
+ nickname and servername, username and hostnamea and users real
+ name. Client should process these replies only after the last
+ reply has been received with the STATUS_LIST_END status. If the
+ <count> option were defined in the query there will be only
+ <count> many replies from the server.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_LIST_START
+ SILC_STATUS_LIST_END
+ SILC_STATUS_ERR_NO_SUCH_NICK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+ 3 SILC_COMMAND_WHOWAS
+
+ Max Arguments: 2
+ Arguments: (1) <nickname>[@<server>] (2) [<count>]
+
+ Whowas. This command is used to query history information about
+ specific user. The user maybe requested by their nickname and
+ server name. The query may find multiple matching users as there
+ are no unique nicknames in the SILC. The <count> option maybe
+ given to narrow down the number of accepted results. If this
+ is not defined there are no limit of accepted results. The query
+ may also be narrowed down by defining the server name of the
+ nickname.
+
+ To prevent miss-use of this service wildcards in the nickname
+ or in the servername are not permitted. The WHOWAS requests must
+ be based on specific nickname request.
+
+ The WHOWAS request must be always forwarded to router by server
+ so that all users are searched. However, the server still must
+ search its locally connected clients.
+
+ Reply messages to the command:
+
+ Max Arguments: 3
+ Arguments: (1) <Status Payload> (2) <nickname>[@<server>]
+ (3) <username@host>
+
+ This command may reply with several command reply messages to form
+ a list of results. In this case the status payload will include
+ STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+ the last reply to indicate the end of the list. If there are only
+ one reply the status is set to normal STATUS_OK.
+
+ The command replies with nickname and username and hostname.
+ Every server must keep history for some period of time of its
+ locally connected clients.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_LIST_START
+ SILC_STATUS_LIST_END
+ SILC_STATUS_ERR_NO_SUCH_NICK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+ 4 SILC_COMMAND_IDENTIFY
+
+ Max Arguments: 2
+ Arguments: (1) <nickname>[@<server>] (2) [<count>]
+
+ Identify. Identify command is almost analogous to WHOIS command,
+ except that it does not return as much information. Only relevant
+ information such as Client ID is returned. This is usually used
+ to get the Client ID of a client used in the communication with
+ the client.
+
+ The query may find multiple matching users as there are no unique
+ nicknames in the SILC. The <count> option maybe given to narrow
+ down the number of accepted results. If this is not defined there
+ are no limit of accepted results. The query may also be narrowed
+ down by defining the server name of the nickname.
+
+ To prevent miss-use of this service wildcards in the nickname
+ or in the servername are not permitted. It is not allowed
+ to request all users on some server. The IDENTIFY requests must
+ be based on specific nickname request.
+
+ Implementations may not want to give interface access to this
+ commands as it is hardly a command that would be used a end user.
+ However, it must be implemented as it is used with private message
+ sending.
+
+ The IDENTIFY must be always forwarded to router by server so that
+ all users are searched. However, server must still search its
+ locally connected clients.
+
+ Reply messages to the command:
+
+ Max Arguments: 4
+ Arguments: (1) <Status Payload> (2) <Client ID>
+ (3) [<nickname>[@<server>]] (4) [<username@host>]
+
+ This command may reply with several command reply messages to form
+ a list of results. In this case the status payload will include
+ STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+ the last reply to indicate the end of the list. If there are only
+ one reply the status is set to normal STATUS_OK.
+
+ The command replies with Client ID of the nickname and if more
+ information is available it may reply with nickname and username
+ and hostname. If the <count> option were defined in the query
+ there will be only <count> many replies from the server.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_LIST_START
+ SILC_STATUS_LIST_END
+ SILC_STATUS_ERR_NO_SUCH_NICK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+ 5 SILC_COMMAND_NICK
+
+ Max Arguments: 1
+ Arguments: (1) <nickname>
+
+ Set/change nickname. This command is used to set nickname for
+ user. There is no limit of the length of the nickname in SILC.
+ Nickname must not include any spaces (` '), non-printable
+ characters, commas (`,') and any wildcard characters. Note:
+ nicknames in SILC are case-sensitive which must be taken into
+ account when searching clients by nickname.
+
+ Reply messages to the command:
+
+ Max Arguments: 2
+ Arguments: (1) <Status Payload> (2) <New ID Payload>
+
+ This command is replied always with New ID Payload that is
+ generated by the server every time user changes their nickname.
+ Client receiving this payload must start using the received
+ Client ID as its current valid Client ID. The New ID Payload
+ is described in [SILC2].
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NICKNAME_IN_USE
+ SILC_STATUS_ERR_BAD_NICKNAME
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+ 6 SILC_COMMAND_LIST
+
+ Max Arguments: 2
+ Arguments: (1) [<Channel ID>] [<server>]
+
+ The list command is used to list channels and their topics on
+ current server. If the <Channel ID> parameter is used, only the
+ status of that channel is displayed. Secret channels are not
+ listed at all. Private channels are listed with status indicating
+ that the channel is private.
+
+ If the <server> argument is specified the specified server's
+ channels are listed. In this case the command must be sent to
+ the server who owns the channel that was requested.
+
+ Reply messages to the command:
+
+ Max Arguments: 3
+ Arguments: (1) <Status Payload> (2) <channel>
+ (3) <topic>
+
+ This command may reply with several command reply messages to form
+ a list of results. In this case the status payload will include
+ STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+ the last reply to indicate the end of the list. If there are only
+ one reply the status is set to normal STATUS_OK.
+
+ This command replies with channel name and the topic of the
+ channel. If the channel is private channel the <topic> includes
+ "*private*" string.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_LIST_START
+ SILC_STATUS_LIST_END
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+ SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+ 7 SILC_COMMAND_TOPIC
+
+ Max Arguments: 2
+ Arguments: (1) <Channel ID> (2) [<server>]]
+
+ This command is used to change or view the topic of a channel.
+ The topic for channel <Channel ID> is returned if there is no
+ <topic> given. If the <topic> parameter is present, the topic
+ for that channel will be changed, if the channel modes permit
+ this action.
+
+ Reply messages to the command:
+
+ Max Arguments: 2
+ Arguments: (1) <Status Payload> (2) [<topic>]
+
+ The command may reply with the topic of the channel if it is
+ set.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ON_CHANNEL
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_ID
+ SILC_STATUS_ERR_BAD_CHANNEL_ID
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+
+ 8 SILC_COMMAND_INVITE
+
+ Max Arguments: 2
+ Arguments: (1) <Client ID> (2) <channel>
+
+ This command is used to invite other clients to join to the
+ channel. There is no requirement that the channel the target
+ client is being invited to must exist or be a valid channel.
+ The <Client ID> argument is the target client's ID that is being
+ invited.
+
+ Reply messages to the command:
+
+ Max Arguments: 2
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ON_CHANNEL
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_RECIPIENT
+ SILC_STATUS_ERR_USER_ON_CHANNEL
+ SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+ 9 SILC_COMMAND_QUIT
+
+ Max Arguments: 1
+ Arguments: (1) [<quit message>]
+
+ This command is used by client to end SILC session. The server
+ must close the connection to a client which sends this command.
+ if <quit message> is given it will be sent to other clients on
+ channel if the client is on channel when quitting.
+
+ Reply messages to the command:
+
+ This command does not reply anything.
+
+
+ 10 SILC_COMMAND_KILL
+
+ Max Arguments: 2
+ Arguments: (1) <Client ID> (2) [<comment>]
+
+ This command is used by SILC operators to remove a client from
+ SILC network. The removing has temporary effects and client may
+ reconnect to SILC network. The <Client ID> is the client to be
+ removed from SILC. The <comment> argument may be provided to
+ give to the removed client some information why it was removed
+ from the network.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+ SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+ 11 SILC_COMMAND_INFO
+
+ Max Arguments: 1
+ Arguments: (1) [<server>]
+
+ This command is used to fetch various information about a server.
+ If <server> argument is specified the command must be sent to
+ the requested server.
+
+ Reply messages to the command:
+
+ Max Arguments: 3
+ Arguments: (1) <Status Payload> (2) <Server ID>
+ (3) <string>
+
+ This command replies with the Server ID of the server and a
+ string which tells the information about the server.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+ SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+
+
+ 12 SILC_COMMAND_CONNECT
+
+ Max Arguments: 2
+ Arguments: (1) <Server ID>
+ (2) [<remote server/router>[:<port>]]
+
+ This command is used by operators to force a server to try to
+ establish a new connection to another router (if the connecting
+ server is normal server) or server (if the conneceting server is
+ router server). Operator may specify the server/router to be
+ connected by setting <remote server> argument.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+ SILC_STATUS_ERR_NO_SERVER_PRIV
+ SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+
+ 13 SILC_COMMAND_PING
+
+ Max Arguments: 1
+ Arguments: (1) <Server ID>
+
+ This command is used by clients to test the communication
+ channel to its server if client suspects that the communication
+ is not working correctly. The <Server ID> is the ID of the
+ server the client is connected to.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload. Server returns
+ SILC_STATUS_OK in Status Payload if pinging was successful.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+ SILC_STATUS_ERR_NOT_REGISTERED
+
+
+ 14 SILC_COMMAND_OPER
+
+ Max Arguments: 2
+ Arguments: (1) <username> (2) <authentication data>
+
+ This command is used by normal client to obtain server operator
+ privileges on some server or router. Note that router operator
+ has router privileges that supersedes the server operator
+ privileges and this does not obtain those privileges. Client
+ must use SILCOPER command to obtain router level privileges.
+
+ The <username> is the username set in the server configurations
+ as operator. The <authentication data> is the data that the
+ client is authenticated against. It may be passphrase prompted
+ for user on client's screen or it may be public key
+ authentication data (data signed with private key), or
+ certificate.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_BAD_PASSWORD
+ SILC_STATUS_ERR_AUTH_FAILED
+
+
+ 15 SILC_COMMAND_JOIN
+
+ Max Arguments: 3
+ Arguments: (1) <channel> (2) [<passphrase>]
+ (3) [<cipher>]
+
+ Join to channel/create new channel. This command is used to
+ join to a channel. If the channel does not exist the channel is
+ created on the server receiving the join request. The channel
+ may be protected with passphrase. If this is the case the
+ passphrase must be sent along the join command.
+
+ The name of the <channel> must not include any spaces (` '),
+ non-printable characters, commas (`,') or any wildcard characters.
+
+ Cipher to be used to secure the traffic on the channel may be
+ requested by sending the name of the requested <cipher>. This
+ is used only if the channel does not exist and is created. If
+ the channel already exists the cipher set previously for the
+ channel will be used to secure the traffic.
+
+ The server must check whether the user is allowed to join to
+ the requested channel. Various modes set to the channel affect
+ the ability of the user to join the channel. These conditions
+ are:
+
+ o The user must be invited to the channel if the channel
+ is invite-only channel.
+
+ o The Client ID/nickname/username/hostname must not match
+ any active bans.
+
+ o The correct passphrase must be provided if passphrase
+ is set to the channel.
+
+ o The user count limit, if set, must not be reached.
+
+ Reply messages to the command:
+
+ Max Arguments: 5
+ Arguments: (1) <Status Payload> (2) <channel>
+ (3) <Channel ID> (4) <channel mode mask>
+ (5) [<topic>]
+
+ This command replies with the channel name requested by the
+ client, channel ID of the channel and topic of the channel
+ if it exists. It also replies with the channel mode mask
+ which tells all the modes set on the channel. If the
+ channel is created the mode mask is zero (0).
+
+ Client must not start transmitting to the channel even after
+ server has replied to this command. Client is permitted to
+ start transmitting on channel after server has sent packet
+ SILC_PACKET_CHANNEL_KEY to the client.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_WILDCARDS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_BAD_PASSWORD
+ SILC_STATUS_ERR_CHANNEL_IS_FULL
+ SILC_STATUS_ERR_NOT_INVITED
+ SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+ SILC_STATUS_ERR_BAD_CHANNEL
+ SILC_STATUS_ERR_USER_ON_CHANNEL
+
+
+ 16 SILC_COMMAND_MOTD
+
+ Max Arguments: 1
+ Arguments: (1) <server>
+
+ This command is used to query the Message of the Day of a server.
+
+ Reply messages to the command:
+
+ Max Arguments: 2
+ Arguments: (1) <Status Payload> (2) [<motd>]
+
+ This command replies with the motd message if it exists.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+ 17 SILC_COMMAND_UMODE
+
+ Max Arguments: 2
+ Arguments: (1) <Client ID> (2) <client mode mask>
+
+ This command is used by client to set/unset modes for itself.
+ However, there are some modes that the client may not set itself,
+ but they will be set by server. However, client may unset any
+ mode. Modes may be masked together ORing them thus having
+ several modes set. Client must keep its client mode mask
+ locally so that the mode setting/unsetting would work without
+ problems. Client may change only its own modes.
+
+ Following client modes are defined:
+
+ 0x0000 SILC_UMODE_NONE
+
+ No specific mode for client. This is the initial
+ setting when new client is created. The client is
+ normal client now.
+
+
+ 0x0001 SILC_UMODE_SERVER_OPERATOR
+
+ Marks the user as server operator. Client cannot
+ set this mode itself. Server sets this mode to the
+ client when client attains the server operator
+ privileges by SILC_COMMAND_OPER command. Client
+ may unset the mode itself.
+
+
+ 0x0002 SILC_UMODE_ROUTER_OPERATOR
+
+ Marks the user as router (SILC) operator. Client
+ cannot this mode itself. Router sets this mode to
+ the client when client attains the router operator
+ privileges by SILC_COMMAND_SILCOPER command. Client
+ may unset the mode itself.
+
+ Reply messages to the command:
+
+ Max Arguments: 2
+ Arguments: (1) <Status Payload> (2) <client mode mask>
+
+ This command replies with the changed client mode mask that
+ the client is required to keep locally.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+ SILC_STATUS_ERR_BAD_CLIENT_ID
+ SILC_STATUS_ERR_NOT_YOU
+ SILC_STATUS_ERR_UNKNOWN_MODE
+ SILC_STATUS_ERR_NO_RECIPIENT
+ SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+ 18 SILC_COMMAND_CMODE
+
+ Max Arguments: 6
+ Arguments: (1) <Channel ID> (2) <channel mode mask>
+ (3) [<user limit>] (4) [<passphrase>]
+ (5) [<Client ID>] (6) [<cipher>[:<key len>]]
+
+ This command is used by client to set or change channel flags on
+ a channel. Channel has several modes that set various properties
+ of a channel. Modes may be masked together by ORing them thus
+ having several modes set. The <Channel ID> is the ID of the
+ target channel. The client changing channel mode must be on
+ the same channel and poses sufficient privileges to be able to
+ change the mode.
+
+ Following channel modes are defined:
+
+ 0x0000 SILC_CMODE_NONE
+
+ No specific mode on channel. This is the default when
+ channel is created. This means that channel is just plain
+ normal channel.
+
+
+ 0x0001 SILC_CMODE_PRIVATE
+
+ Channel is private channel. Private channels are shown
+ in the channel list listed with SILC_COMMAND_LIST command
+ with indicatioin that the channel is private. Also,
+ client on private channel will no be detected to be on
+ the channel as the channel is not shown in the client's
+ currently joined channel list. Channel founder and
+ channel operator may set/unset this mode.
+
+ Typical implementation would use [+|-]p on user interface
+ to set/unset this mode.
+
+
+ 0x0002 SILC_CMODE_SECRET
+
+ Channel is secret channel. Secret channels are not shown
+ in the list listed with SILC_COMMAND_LIST command. Secret
+ channels can be considered to be invisible channels.
+ Channel founder and channel operator may set/unset this
+ mode.
+
+ Typical implementation would use [+|-]s on user interface
+ to set/unset this mode.
+
+
+ 0x0004 SILC_CMODE_PRIVKEY
+
+ Channel uses private channel key to protect the traffic
+ on the channel. When this mode is set the client will be
+ responsible to set the key it wants to use to encrypt and
+ decrypt the traffic on channel. Server generated channel
+ keys are not used at all. This mode provides additional
+ security as clients on channel may agree to use private
+ channel key that even servers do not know. Naturally,
+ this requires that every client on the channel knows
+ the key before hand (it is considered to be pre-shared-
+ key). This specification does not define how the private
+ channel key is set as it is entirely local setting on
+ client end.
+
+ As it is local setting it is possible to have several
+ private channel keys on one channel. In this case several
+ clients can talk on same channel but only those clients
+ that share the key with the message sender will be able
+ to hear the talking. Client should not display those
+ message for the end user that it is not able to decrypt
+ when this mode is set.
+
+ Only channel founder may set/unset this mode. If this
+ mode is unset the server will distribute new channel
+ key to all clients on the channel which will be used
+ thereafter.
+
+ Typical implementation would use [+|-]k on user interface
+ to set/unset this mode.
+
+
+ 0x0008 SILC_CMODE_INVITE
+
+ Channel is invite only channel. Client may join to this
+ channel only if it is invited to the channel. Channel
+ founder and channel operator may set/unset this mode.
+
+ Typical implementation would use [+|-]i on user interface
+ to set/unset this mode.
+
+
+ 0x0010 SILC_CMODE_TOPIC
+
+ The topic of the channel may only be set by client that
+ is channel founder or channel operator. Normal clients
+ on channel will not be able to set topic when this mode
+ is set. Channel founder and channel operator may set/
+ unset this mode.
+
+ Typical implementation would use [+|-]t on user interface
+ to set/unset this mode.
+
+
+ 0x0020 SILC_CMODE_ULIMIT
+
+ User limit has been set to the channel. New clients
+ may not join to the channel when the limit set is
+ reached. Channel founder and channel operator may set/
+ unset the limit. The <user limit> argument is the
+ number of limited users.
+
+ Typical implementation would use [+|-]l on user interface
+ to set/unset this mode.
+
+
+ 0x0040 SILC_CMODE_PASSPHRASE
+
+ Passphrase has been set to the channel. Client may
+ join to the channel only if it is able to provide the
+ correct passphrase. Setting passphrases to channel
+ is entirely safe as all commands are protected in the
+ SILC network. Only channel founder may set/unset
+ the passphrase. The <passphrase> argument is the
+ set passphrase.
+
+ Typical implementation would use [+|-]a on user interface
+ to set/unset this mode.
+
+
+ 0x0080 SILC_CMODE_BAN
+
+ Ban mask has been set to the channel. The ban mask
+ may be used to ban specific clients to join the channel.
+ The <ban mask> argument is the set ban mask. When
+ unsetting a ban mask the mask must be provided as
+ argument. Channel founder and channel operator may
+ set/unset this mode. Channel founder may not be
+ added to the ban list.
+
+ Typical implementation would use [+|-]b on user interface
+ to set/unset this mode.
+
+
+ 0x0100 SILC_CMODE_OPERATOR
+
+ Sets channel operator privileges on the channel for a
+ client on the channel. The <Client ID> argument is the
+ target client on the channel. Channel founder and
+ channel operator may set/unset (promote/demote) this
+ mode.
+
+ Typical implementation would use [+|-]o on user interface
+ to set/unset this mode.
+
+
+ 0x0200 SILC_CMODE_CIPHER
+
+ Sets specific cipher to be used to protect channel
+ traffic. The <cipher> argument is the requested cipher.
+ When set or unset the server must re-generate new
+ channel key. If <key len> argument is specified with
+ <cipher> argument the new key is generated of <key len>
+ length.
+
+ Typical implementation would use [+|-]c on user interface
+ to set/unset this mode.
+
+
+ To make the mode system work, client must keep the channel mode
+ mask locally so that the mode setting and unsetting would work
+ without problems. The client receives the initial channel mode
+ mask when it joins to the channel. When the mode changes on
+ channel the server distributes the changed channel mode mask to
+ all clients on the channel by sending SILC_COMMAND_CMODE command
+ reply packet.
+
+ Reply messages to the command:
+
+ Max Arguments: 2
+ Arguments: (1) <Status Payload> (2) <channel mode mask>
+
+ This command replies with the changed channel mode mask that
+ client is required to keep locally. The same mask is also
+ sent to all clients on channel by sending additional command
+ reply to them.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ON_CHANNEL
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+ SILC_STATUS_ERR_BAD_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV
+ SILC_STATUS_ERR_UNKNOWN_MODE
+ SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+ 19 SILC_COMMAND_KICK
+
+ Max Arguments: 3
+ Arguments: (1) <channel> (2) <Client ID>
+ (3) [<comment>]
+
+ This command is used by channel operators to remove a client from
+ channel. The <channel> argument is the channel the client to be
+ removed is on currently. Note that the "kicker" must be on the same
+ channel. If <comment> is provided it will be sent to the removed
+ client.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV
+ SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+ 20 SILC_COMMAND_RESTART
+
+ Max Arguments: 0
+ Arguments: None
+
+ This command may only be used by server operator to force a
+ server to restart itself.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NO_SERVER_PRIV
+
+
+ 21 SILC_COMMAND_CLOSE
+
+ Max Arguments: 1
+ Arguments: (1) <Server ID>
+
+ This command is used only by operator to close connection to a
+ remote site. The <Server ID> argument is the ID of the remote
+ site and must be valid.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NO_SUCH_SERVER
+ SILC_STATUS_ERR_NO_SERVER_PRIV
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+
+ 22 SILC_COMMAND_DIE
+
+ Max Arguments: 0
+ Arguments: None
+
+ This command is used only by operator to shutdown the server.
+ All connections to the server will be closed and the server is
+ shutdown.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NO_SERVER_PRIV
+
+
+ 23 SILC_COMMAND_SILCOPER
+
+ Max Arguments: 2
+ Arguments: (1) <username> (2) <authentication data>
+
+ This command is used by normal client to obtain router operator
+ privileges (also known as SILC operator) on some router. Note
+ that router operator has router privileges that supersedes the
+ server operator privileges.
+
+ The <username> is the username set in the server configurations
+ as operator. The <authentication data> is the data that the
+ client is authenticated against. It may be passphrase prompted
+ for user on client's screen or it may be public key
+ authentication data (data signed with private key), or
+ certificate.
+
+ Difference between router operator and server operator is that
+ router operator is able to handle cell level properties while
+ server operator (even on router server) is able to handle only
+ local properties, such as, local connections and normal server
+ administration.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_BAD_PASSWORD
+ SILC_STATUS_ERR_AUTH_FAILED
+
+
+ 24 SILC_COMMAND_LEAVE
+
+ Max Arguments: 1
+ Arguments: (1) <Channel ID>
+
+ This command is used by client to leave a channel the client is
+ joined to. After a client has leaved the channel the server
+ must create new key for the channel and distribute to all clients
+ still currently on the channel.
+
+ Reply messages to the command:
+
+ Max Arguments: 1
+ Arguments: (1) <Status Payload>
+
+ This command replies only with Status Payload.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+ SILC_STATUS_ERR_BAD_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_ID
+
+
+ 25 SILC_COMMAND_NAMES
+
+ Max Arguments: 1
+ Arguments: (1) <Channel ID>
+
+ This command is used to list user names currently on the requested
+ channel; argument <Channel ID>. The server must resolve the
+ user names and send a comma (`,') separated list of user names
+ on the channel. Server or router may resolve the names by sending
+ SILC_COMMAND_WHOIS commands.
+
+ If the requested channel is a private or secret channel, this
+ command must not send the list of users, as private and secret
+ channels cannot be seen by outside. In this case the returned
+ name list may include a indication that the server could not
+ resolve the names of the users on the channel.
+
+ Reply messages to the command:
+
+ Max Arguments: 2
+ Arguments: (1) <Status Payload> (2) <name list>
+
+ This command replies with the comma separated list of users on
+ the channel.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+ SILC_STATUS_ERR_BAD_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_ID
+ SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+
+ 26 - 254
+
+ Currently undefined commands.
+
+
+ 255 SILC_COMMAND_MAX
+
+ Reserved command. This must not be sent.
+.in 3
+
+
+.ti 0
+5.3 SILC Command Status Types
+
+.ti 0
+5.3.1 SILC Command Status Payload
+
+Command Status Payload is sent in command reply messages to indicate
+the status of the command. The payload is one of argument in the
+command thus this is the data area in Command Argument Payload described
+in [SILC2]. The payload is only 2 bytes of length. Following diagram
+represents the Command Status Payload (field is always in MSB order).
+
+
+.in 21
+.nf
+ 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Status Message |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5: SILC Command Status Payload
+
+
+.in 6
+o Status Message (2 bytes) - Indicates the status message.
+ All Status messages are described in the next section.
+.in 3
+
+
+.ti 0
+5.3.2 SILC Command Status List
+
+Command Status messages are returned in the command reply messages
+to indicate whether the command were executed without errors. If error
+has occured the status tells which error occured. Status payload only
+sends numeric reply about the status. Receiver of the payload must
+convert the numeric values into human readable error messages. The
+list of status messages below has an example human readable error
+messages that client may display for the user.
+
+List of all defined command status messages following.
+
+.in 0
+ Generic status messages:
+
+ 0 SILC_STATUS_OK
+
+ Ok status. Everything went Ok. The status payload maybe
+ safely ignored in this case.
+
+ 1 SILC_STATUS_LIST_START
+
+ Start of the list. There will be several command replies and
+ this reply is the start of the list.
+
+ 2 SILC_STATUS_LIST_END
+
+ End of the list. There were several command replies and this
+ reply is the last of the list. There won't be other replies
+ beloning to this list after this one.
+
+ 3 - 9
+
+ Currently undefined and has been reserved for the future.
+
+
+ Error status message:
+
+ 10 SILC_STATUS_ERR_NO_SUCH_NICK
+
+ "No such nickname". Requested nickname does not exist.
+
+ 11 SILC_STATUS_ERR_NO_SUCH_CHANNEL
+
+ "No such channel". Requested channel name does not exist.
+
+ 12 SILC_STATUS_ERR_NO_SUCH_SERVER
+
+ "No such server". Requested server name does not exist.
+
+ 13 SILC_STATUS_ERR_TOO_MANY_TARGETS
+
+ "Duplicate recipients. No message delivered". Message were
+ tried to be sent to recipient which has several occurrences in
+ the recipient list.
+
+ 14 SILC_STATUS_ERR_NO_RECIPIENT
+
+ "No recipient given". Command required recipient which was
+ not provided.
+
+ 15 SILC_STATUS_ERR_UNKNOWN_COMMAND
+
+ "Unknown command". Command sent to server is unknown by the
+ server.
+
+ 16 SILC_STATUS_ERR_WILDCARDS
+
+ "Wildcards cannot be used". Wildcards were provided but they
+ weren't permitted.
+
+ 17 SILC_STATUS_ERR_NO_CLIENT_ID
+
+ "No Client ID given". Client ID were expected as command
+ parameter but were not found.
+
+ 18 SILC_STATUS_ERR_NO_CHANNEL_ID
+
+ "No Channel ID given". Channel ID were expected as command
+ parameter but were not found.
+
+ 19 SILC_STATUS_ERR_BAD_CLIENT_ID
+
+ "Bad Client ID". Client ID provided were erroneous.
+
+ 20 SILC_STATUS_ERR_BAD_CHANNEL_ID
+
+ "Bad Channel ID". Channel ID provided were erroneous.
+
+ 21 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+ "No such Client ID". Client ID provided does not exist.
+
+
+
+ 22 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+
+ "No such Channel ID". Channel ID provided does not exist.
+
+ 23 SILC_STATUS_ERR_NICKNAME_IN_USE
+
+ "Nickname already exists". Nickname created could not be
+ registered because number of same nicknames were already set to
+ maximum. This is not expected to happen in real life but is
+ possible to occur.
+
+ 24 SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+ "You are not on that channel". The command were specified for
+ client user is not currently on.
+
+ 25 SILC_STATUS_ERR_USER_ON_CHANNEL
+
+ "User already on channel". User were invited on channel they
+ already are on.
+
+ 26 SILC_STATUS_ERR_NOT_REGISTERED
+
+ "You have not registered". User executed command that requires
+ the client to be registered on the server before it may be
+ executed.
+
+ 27 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+
+ "Not enough parameters". Command requires more parameters
+ than provided.
+
+ 28 SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+ "Too many parameters". Too many parameters were provided
+ for the command.
+
+ 29 SILC_STATUS_ERR_PERM_DENIED
+
+ "Your host is not among the privileged". The client tried to
+ register on server that does not allow this host to connect.
+
+ 30 SILC_STATUS_ERR_BANNED_FROM_SERVER
+
+ "You are banned from this server". The client tried to register
+ on server that has explicitly denied this host to connect.
+
+
+
+ 31 SILC_STATUS_ERR_BAD_PASSWORD
+
+ "Cannot join channel. Incorrect password". Password provided for
+ channel were not accepted.
+
+ 32 SILC_STATUS_ERR_CHANNEL_IS_FULL
+
+ "Cannot join channel. Channel is full". The channel is full
+ and client cannot be joined to it.
+
+ 33 SILC_STATUS_ERR_NOT_INVITED
+
+ "Cannot join channel. You have not been invited". The channel
+ is invite only channel and client has not been invited.
+
+ 34 SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+
+ "Cannot join channel. You have been banned". The client has
+ been banned from the channel.
+
+ 35 SILC_STATUS_ERR_UNKNOWN_MODE
+
+ "Unknown mode". Mode provided by the client were unknown to
+ the server.
+
+ 36 SILC_STATUS_ERR_NOT_YOU
+
+ "Cannot change mode for other users". User tried to change
+ someone else's mode.
+
+ 37 SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+ "Permission denied. You are not channel operator". Command may
+ be executed only by channel operator.
+
+ 38 SILC_STATUS_ERR_NO_SERVER_PRIV
+
+ "Permission denied. You are not server operator". Command may
+ be executed only by server operator.
+
+ 39 SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+ "Permission denied. You are not SILC operator". Command may be
+ executed only by router (SILC) operator.
+
+ 40 SILC_STATUS_ERR_BAD_NICKNAME
+
+ "Bad nickname". Nickname requested contained illegal characters
+ or were malformed.
+
+ 41 SILC_STATUS_ERR_BAD_CHANNEL
+
+ "Bad channel name". Channel requested contained illegal characters
+ or were malformed.
+
+ 42 SILC_STATUS_ERR_AUTH_FAILED
+
+ "Authentication failed". The authentication data sent as
+ argument were wrong and thus authentication failed.
+.in 3
+
+
+.ti 0
+6 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+7 References
+
+[SILC2] Riikonen, P., "SILC Packet Protocol", Internet Draft,
+ June 2000.
+
+[SILC3] Riikonen, P., "SILC Key Exchange and Authentication
+ Protocols", Internet Draft, June 2000.
+
+[IRC] Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+ RFC 1459, May 1993.
+
+[SSH-TRANS] Ylonen, T., et al, "SSH Transport Layer Protocol",
+ Internet Draft.
+
+[PGP] Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+ November 1998.
+
+[SPKI] Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+ September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+ Infrastructure, Certificate and CRL Profile", RFC 2459,
+ January 1999.
+
+[Schneier] Schneier, B., "Applied Cryptography Second Edition",
+ John Wiley & Sons, New York, NY, 1996.
+
+[Menezes] Menezes, A., et al, "Handbook of Applied Cryptography",
+ CRC Press 1997.
+
+[OAKLEY] Orman, H., "The OAKLEY Key Determination Protocol",
+ RFC 2412, November 1998.
+
+[ISAKMP] Maughan D., et al, "Internet Security Association and
+ Key Management Protocol (ISAKMP)", RFC 2408, November
+ 1998.
+
+[IKE] Harkins D., and Carrel D., "The Internet Key Exhange
+ (IKE)", RFC 2409, November 1998.
+
+[HMAC] Krawczyk, H., "HMAC: Keyed-Hashing for Message
+ Authentication", RFC 2104, February 1997.
+
+
+.ti 0
+8 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
--- /dev/null
+#
+# Configured ciphers.
+#
+# Format: <name>:<module path>:<key length>:<block length>
+#
+# If the cipher is builtin the <module path> maybe omitted.
+#
+[cipher]
+twofish-cbc:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6-cbc:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars-cbc:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+#
+# Configured hash functions.
+#
+# Format: <name>:<module path>:<block length>:<digest length>
+#
+# If the hash function is builtin the <module path> maybe omitted.
+#
+[hash]
+md5::64:16
+sha1::64:20
+
+#
+# Configured PKCS.
+#
+# Format: <name>:<module path>:<key length>
+#
+# NOTE: <module path> must be omitted as PKCS cannot be modules currently.
+#
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+#
+# Configured connections to servers.
+#
+# Format: <remote host>:<auth type>:<auth data>:<port>
+#
+# <auth type> maybe `passwd' or `pubkey'.
+#
+[connection]
+#lassi.kuo.fi.ssh.com:passwd::1333
+
+#
+# Commands. These are executed when SILC client is run. Normal
+# SILC commands may be executed here.
+#
+# Format: <command>
+#
+[commands]
+/server silc.pspt.fi
--- /dev/null
+#
+# Configured ciphers.
+#
+# Format: <name>:<module path>:<key length>:<block length>
+#
+# If the cipher is builtin the <module path> maybe omitted.
+#
+[cipher]
+twofish-cbc:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6-cbc:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars-cbc:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+#
+# Configured hash functions.
+#
+# Format: <name>:<module path>:<block length>:<digest length>
+#
+# If the hash function is builtin the <module path> maybe omitted.
+#
+[hash]
+md5::64:16
+sha1::64:20
+
+#
+# Configured PKCS.
+#
+# Format: <name>:<module path>:<key length>
+#
+# NOTE: <module path> must be omitted as PKCS cannot be modules currently.
+#
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+#
+# Server's administrative information.
+#
+# Format: <location>:<server type>:<admin's name>:<admin's email address>
+#
+[AdminInfo]
+Kuopio, Finland:Test Server:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+#
+# Server information.
+#
+# Format: +<server FQDN>:<server IP>:<geographic location>:<port>
+#
+[ServerInfo]
+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+
+#
+# Listenning ports.
+#
+# Format: <local IP/UNIX socket path>:<remote IP>:<port>
+#
+[ListenPort]
+10.2.1.6:10.2.1.6:1333
+
+#
+# Log files.
+#
+# This section is used to set various logging files, their paths
+# and maximum sizes. All the other directives except those defined
+# below are ignored in this section. Log files are purged after they
+# reach the maximum set byte size.
+#
+# Format: infologfile:<path>:<max byte size>
+# warninglogile:<path>:<max byte size>
+# errorlogile:<path>:<max byte size>
+# fatallogile:<path>:<max byte size>
+#
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+#errorlogfile:ERROR.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+#
+# Connection classes.
+#
+# This section is used to define connection classes. These can be
+# used to optimize the server and the connections.#
+#
+# Format: <class number>:<ping freq>:<connect freq>:<max links>
+#
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+#
+# Configured client connections.
+#
+# Format: <remote host>:<auth method>:<auth data>:<port>:<class>
+#
+[ClientConnection]
+:::1333:1
+
+#
+# Configured server administrator connections
+#
+# Format: <host>:<auth method>:<auth data>:<nickname hash>:<class>
+#
+[AdminConnection]
+10.2.1.199:passwd:veryscret:XXX:1
+
+#
+# Configured server connections.
+#
+# If server connections are configured it means that our server is
+# router server. Normal server must not configure server connections.
+# Thus, if your server is not router do not configure this section. If
+# your server is router, this must be configured.
+#
+# Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:<vlass>
+#
+[ServerConnection]
+10.2.1.7:passwd:veryscret:1333:1:1
+
+#
+# Configured router connections.
+#
+# For normal server only one entry maybe configured to this section. It
+# must be the router this server will be connected to. For router server,
+# this sections includes all configured router connections. The first
+# configured connection is the primary route.
+#
+# Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:<class>
+#
+[RouterConnection]
+10.2.1.100:passwd:veryverysecret:1333:1:1
+
+#
+# Denied connections.
+#
+# These connections are denied to connect our server.
+#
+# Format: <remote host/nickname>:<time interval>:<comment>:<port>
+#
+[DenyConnection]
+
+#
+# Redirected client connections.
+#
+# Clients will be redirected to these servers when our server is full.
+#
+# Format: <remote host>:<port>
+#
+[RedirectClient]
--- /dev/null
+#!/usr/bin/perl
+
+# fix.pl 17-Nov-93 Craig Milo Rogers at USC/ISI
+#
+# The style guide for RFCs calls for pages to be delimited by the
+# sequence <last-non-blank-line><formfeed-line><first-non-blank-line>.
+# Unfortunately, NROFF is reluctant to produce output that conforms to
+# this convention. This script fixes RFC-style documents by searching
+# for the token "FORMFEED[Page", replacing "FORMFEED" with spaces,
+# appending a formfeed line, and deleting white space up to the next
+# non-white space character.
+#
+# There is one difference between this script's output and that of
+# the "fix.sh" and "pg" programs it replaces: this script includes a
+# newline after the formfeed after the last page in a file, whereas the
+# earlier programs left a bare formfeed as the last character in the
+# file. To obtain bare formfeeds, uncomment the second substitution
+# command below. To strip the final formfeed, uncomment the third
+# substitution command below.
+#
+# This script is intended to run as a filter, as in:
+#
+# nroff -ms input-file | fix.pl > output-file
+#
+# When porting this script, please observe the following points:
+#
+# 1) ISI keeps perl in "/local/bin/perl"; your system may keep it
+# elsewhere.
+# 2) On systems with a CRLF end-of-line convention, the "0s below
+# may have to be replaced with "^[70s.
+
+$* = 1; # Enable multiline patterns.
+undef $/; # Read whole files in a single
+ # gulp.
+
+while (<>) { # Read the entire input file.
+ s/FORMFEED(\[Page\s+\d+\])\s+/ \1\n\f\n/g;
+ s/\f\n$/\f/; # Want bare formfeed at end?
+ print; # Print the resultant file.
+}
--- /dev/null
+#!/bin/sh
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Creates RFC
+#
+# Usage: makerfc <input_file> <output_file>
+#
+nroff -ms $1 | ./fix.pl > $2
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+all:
+ -cd ..
+
+EXTRA_DIST = *.h
\ No newline at end of file
--- /dev/null
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+EXTRA_DIST = *.h
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = silcdefs.h
+CONFIG_CLEAN_FILES =
+DIST_COMMON = Makefile.am Makefile.in silcdefs.h.in stamp-h.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile silcdefs.h
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign includes/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+silcdefs.h: stamp-h
+ @:
+stamp-h: $(srcdir)/silcdefs.h.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES= CONFIG_HEADERS=includes/silcdefs.h \
+ $(SHELL) ./config.status
+ @echo timestamp > stamp-h
+$(srcdir)/silcdefs.h.in: $(srcdir)/stamp-h.in
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ @echo timestamp > $(srcdir)/stamp-h.in
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+ -rm -f silcdefs.h
+
+maintainer-clean-hdr:
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = includes
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file; \
+ done
+info:
+dvi:
+check: all
+ $(MAKE)
+installcheck:
+install-exec:
+ @$(NORMAL_INSTALL)
+
+install-data:
+ @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+ @:
+
+uninstall:
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(DISTCLEANFILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-hdr mostlyclean-generic
+
+clean: clean-hdr clean-generic mostlyclean
+
+distclean: distclean-hdr distclean-generic clean
+ -rm -f config.status
+
+maintainer-clean: maintainer-clean-hdr maintainer-clean-generic \
+ distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+tags distdir info dvi installcheck install-exec install-data install \
+uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+all:
+ -cd ..
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+
+ bitmove.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef BITMOVE_H
+#define BITMOVE_H
+
+/* Returns four 8-bit bytes, most significant bytes first. */
+#define SILC_GET32_MSB(l, cp) \
+ (l) = ((unsigned long)(unsigned char)(cp)[0]) << 24 \
+ | ((unsigned long)(unsigned char)(cp)[1] << 16) \
+ | ((unsigned long)(unsigned char)(cp)[2] << 8) \
+ | ((unsigned long)(unsigned char)(cp)[3])
+#define SILC_PUT32_MSB(l, cp) \
+ (cp)[0] = l >> 24; \
+ (cp)[1] = l >> 16; \
+ (cp)[2] = l >> 8; \
+ (cp)[3] = l;
+
+
+/* Returns four 8-bit bytes, less significant bytes first. */
+#define SILC_GET32_LSB(l, cp) \
+ (l) = ((unsigned long)(unsigned char)(cp)[0]) \
+ | ((unsigned long)(unsigned char)(cp)[1] << 8) \
+ | ((unsigned long)(unsigned char)(cp)[2] << 16) \
+ | ((unsigned long)(unsigned char)(cp)[3] << 24)
+/* same as upper but XOR the result always */
+#define SILC_GET32_X_LSB(l, cp) \
+ (l) ^= ((unsigned long)(unsigned char)(cp)[0]) \
+ | ((unsigned long)(unsigned char)(cp)[1] << 8) \
+ | ((unsigned long)(unsigned char)(cp)[2] << 16) \
+ | ((unsigned long)(unsigned char)(cp)[3] << 24)
+#define SILC_PUT32_LSB(l, cp) \
+ (cp)[0] = l; \
+ (cp)[1] = l >> 8; \
+ (cp)[2] = l >> 16; \
+ (cp)[3] = l >> 24;
+
+
+/* Returns two 8-bit bytes, most significant bytes first. */
+#define SILC_GET16_MSB(l, cp) \
+ (l) = ((unsigned long)(unsigned char)(cp)[0] << 8) \
+ | ((unsigned long)(unsigned char)(cp)[1])
+#define SILC_PUT16_MSB(l, cp) \
+ (cp)[0] = l >> 8; \
+ (cp)[1] = l;
+
+/* Returns two 8-bit bytes, less significant bytes first. */
+#define SILC_GET16_LSB(l, cp) \
+ (l) = ((unsigned long)(unsigned char)(cp)[0]) \
+ | ((unsigned long)(unsigned char)(cp)[1] << 8)
+#define SILC_PUT16_LSB(l, cp) \
+ (cp)[0] = l; \
+ (cp)[1] = l >> 8;
+
+#endif
--- /dev/null
+/*
+
+ clientincludes.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENTINCLUDES_H
+#define CLIENTINCLUDES_H
+
+#include <curses.h>
+#include <paths.h>
+#include <sys/param.h>
+#include <pwd.h>
+
+/* Generic includes */
+#include "silcincludes.h"
+
+/* SILC Client includes */
+#include "idlist.h"
+#include "screen.h"
+#include "clientconfig.h"
+#include "client.h"
+#include "clientutil.h"
+#include "protocol.h"
+#include "command.h"
+#include "command_reply.h"
+#include "silc.h"
+
+#endif
--- /dev/null
+/*
+
+ serverincludes.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERVERINCLUDES_H
+#define SERVERINCLUDES_H
+
+/* Generic includes */
+#include "silcincludes.h"
+
+/* SILC Server includes */
+#include "idlist.h"
+#include "route.h"
+#include "serverid.h"
+#include "serverconfig.h"
+#include "server.h"
+#include "protocol.h"
+#include "command.h"
+#include "command_reply.h"
+#include "silcd.h"
+
+#endif
--- /dev/null
+/* includes/silcdefs.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define as __inline if that's what the C compiler calls it. */
+#undef inline
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef mode_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#undef STAT_MACROS_BROKEN
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Name of the package. */
+#undef PACKAGE
+
+/* Version of the package. */
+#undef VERSION
+
+/* Debugging */
+#undef SILC_DEBUG
+
+/* Default configuration file */
+#undef SILC_SERVER_CONFIG_FILE
+
+/* SIM (SILC Module) support */
+#undef SILC_SIM
+#undef HAVE_RTLD_NOW
+#undef HAVE_RTLD_LAZY
+
+/* Define if you have the bind function. */
+#undef HAVE_BIND
+
+/* Define if you have the chmod function. */
+#undef HAVE_CHMOD
+
+/* Define if you have the close function. */
+#undef HAVE_CLOSE
+
+/* Define if you have the connect function. */
+#undef HAVE_CONNECT
+
+/* Define if you have the ctime function. */
+#undef HAVE_CTIME
+
+/* Define if you have the fcntl function. */
+#undef HAVE_FCNTL
+
+/* Define if you have the fstat function. */
+#undef HAVE_FSTAT
+
+/* Define if you have the getenv function. */
+#undef HAVE_GETENV
+
+/* Define if you have the getgid function. */
+#undef HAVE_GETGID
+
+/* Define if you have the gethostbyaddr function. */
+#undef HAVE_GETHOSTBYADDR
+
+/* Define if you have the gethostbyname function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define if you have the gethostname function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define if you have the getopt_long function. */
+#undef HAVE_GETOPT_LONG
+
+/* Define if you have the getpgid function. */
+#undef HAVE_GETPGID
+
+/* Define if you have the getpgrp function. */
+#undef HAVE_GETPGRP
+
+/* Define if you have the getpid function. */
+#undef HAVE_GETPID
+
+/* Define if you have the getservbyname function. */
+#undef HAVE_GETSERVBYNAME
+
+/* Define if you have the getservbyport function. */
+#undef HAVE_GETSERVBYPORT
+
+/* Define if you have the getsid function. */
+#undef HAVE_GETSID
+
+/* Define if you have the gettimeofday function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if you have the getuid function. */
+#undef HAVE_GETUID
+
+/* Define if you have the listen function. */
+#undef HAVE_LISTEN
+
+/* Define if you have the memcpy function. */
+#undef HAVE_MEMCPY
+
+/* Define if you have the memmove function. */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the memset function. */
+#undef HAVE_MEMSET
+
+/* Define if you have the mlock function. */
+#undef HAVE_MLOCK
+
+/* Define if you have the munlock function. */
+#undef HAVE_MUNLOCK
+
+/* Define if you have the putenv function. */
+#undef HAVE_PUTENV
+
+/* Define if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define if you have the setsockopt function. */
+#undef HAVE_SETSOCKOPT
+
+/* Define if you have the shutdown function. */
+#undef HAVE_SHUTDOWN
+
+/* Define if you have the socket function. */
+#undef HAVE_SOCKET
+
+/* Define if you have the stat function. */
+#undef HAVE_STAT
+
+/* Define if you have the strchr function. */
+#undef HAVE_STRCHR
+
+/* Define if you have the strcpy function. */
+#undef HAVE_STRCPY
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strncpy function. */
+#undef HAVE_STRNCPY
+
+/* Define if you have the strstr function. */
+#undef HAVE_STRSTR
+
+/* Define if you have the time function. */
+#undef HAVE_TIME
+
+/* Define if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define if you have the <assert.h> header file. */
+#undef HAVE_ASSERT_H
+
+/* Define if you have the <ctype.h> header file. */
+#undef HAVE_CTYPE_H
+
+/* Define if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Define if you have the <ncurses.h> header file. */
+#undef HAVE_NCURSES_H
+
+/* Define if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have the <termcap.h> header file. */
+#undef HAVE_TERMCAP_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
--- /dev/null
+/*
+
+ silcincludes.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ This file includes common definitions for SILC. This file MUST be included
+ by all files in SILC (directly or through other global include file).
+*/
+
+#ifndef SILCINCLUDES_H
+#define SILCINCLUDES_H
+
+/* Automatically generated configuration header */
+#include "silcdefs.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#error getopt.h not found in the system
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#else
+#error signal.h not found in the system
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#error fcntl.h not found in the system
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <errno.h>
+#else
+#error errno.h not found in the system
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#else
+#error assert.h not found in the system
+#endif
+
+#include <sys/socket.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#else
+#error netinet/in.h not found in the system
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#else
+#error netinet/tcp.h not found in the system
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#else
+#error netdb.h not found in the system
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#else
+#error arpa/inet.h not found in the system
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* Generic global SILC includes */
+#include "bitmove.h"
+
+/* Math library includes */
+#include "silcmp.h"
+#include "modinv.h"
+#include "silcprimegen.h"
+
+/* Crypto library includes */
+#include "silccipher.h"
+#include "silchash.h"
+#include "silchmac.h"
+#include "silcrng.h"
+#include "silcpkcs.h"
+
+/* SILC core library includes */
+#include "silclog.h"
+#include "silcmemory.h"
+#include "silcbuffer.h"
+#include "silcbufutil.h"
+#include "silcbuffmt.h"
+#include "silcnet.h"
+#include "silcutil.h"
+#include "silcconfig.h"
+#include "id.h"
+#include "idcache.h"
+#include "silcpacket.h"
+#include "silctask.h"
+#include "silcschedule.h"
+#include "silcprotocol.h"
+#include "silccommand.h"
+#include "silcchannel.h"
+#include "silcsockconn.h"
+
+#ifdef SILC_SIM
+/* SILC Module library includes */
+#include "silcsim.h"
+#include "silcsimutil.h"
+#endif
+
+/* SILC Key Exchange library includes */
+#include "silcske.h"
+#include "payload.h"
+#include "groups.h"
+
+#endif
--- /dev/null
+/*
+
+ version.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef VERSION_H
+#define VERSION_H
+
+/* Version type definition */
+typedef unsigned char SilcVersion;
+
+/* SILC Versions. XXX not used currently */
+#define SILC_VERSION_MAJ 1
+#define SILC_VERSION_MIN 0
+#define SILC_VERSION_BUILD 0
+
+/* SILC Protocol version number used in SILC packets */
+#define SILC_VERSION_1 '\1'
+
+/* SILC version string */
+const char *silc_version = "27062000";
+const char *silc_name = "SILC";
+const char *silc_fullname = "Secure Internet Live Conferencing";
+
+#endif
--- /dev/null
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+SUBDIRS = \
+ silccore \
+ silccrypt \
+ silcsim \
+ silcmath \
+ silcske
+# zlib
+
+CLEANFILES = libsilc.a
+DISTCLEANFILES = libsilc.a
+
+all: libsilc.a
+
+libsilc.a:
+ find . -type f -name *.o | xargs $(AR) cru libsilc.a
+ ranlib libsilc.a
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilccore.a
+
+libsilccore_a_SOURCES = \
+ id.c \
+ idcache.c \
+ silcbuffer.c \
+ silcbuffmt.c \
+ silcbufutil.c \
+ silcchannel.c \
+ silccommand.c \
+ silcconfig.c \
+ silclog.c \
+ silcmemory.c \
+ silcnet.c \
+ silcpacket.c \
+ silcprotocol.c \
+ silcschedule.c \
+ silcsockconn.c \
+ silctask.c \
+ silcutil.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
+ -I../silcsim -I../.. -I../../includes \
+ -I../silcmath/gmp-3.0.1
--- /dev/null
+/*
+
+ id.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Converts ID to string. */
+
+unsigned char *silc_id_id2str(void *id, SilcIdType type)
+{
+ unsigned char *ret_id;
+ SilcServerID *server_id;
+ SilcClientID *client_id;
+ SilcChannelID *channel_id;
+
+ switch(type) {
+ case SILC_ID_SERVER:
+ server_id = (SilcServerID *)id;
+ ret_id = silc_calloc(8, sizeof(unsigned char));
+ SILC_PUT32_MSB(server_id->ip.s_addr, ret_id);
+ SILC_PUT16_MSB(server_id->port, &ret_id[4]);
+ SILC_PUT16_MSB(server_id->rnd, &ret_id[6]);
+ return ret_id;
+ break;
+ case SILC_ID_CLIENT:
+ client_id = (SilcClientID *)id;
+ ret_id = silc_calloc(16, sizeof(unsigned char));
+ SILC_PUT32_MSB(client_id->ip.s_addr, ret_id);
+ ret_id[4] = client_id->rnd;
+ memcpy(&ret_id[5], client_id->hash, CLIENTID_HASH_LEN);
+ return ret_id;
+ break;
+ case SILC_ID_CHANNEL:
+ channel_id = (SilcChannelID *)id;
+ ret_id = silc_calloc(8, sizeof(unsigned char));
+ SILC_PUT32_MSB(channel_id->ip.s_addr, ret_id);
+ SILC_PUT16_MSB(channel_id->port, &ret_id[4]);
+ SILC_PUT16_MSB(channel_id->rnd, &ret_id[6]);
+ return ret_id;
+ break;
+ }
+
+ return NULL;
+}
+
+/* Converts string to a ID */
+
+void *silc_id_str2id(unsigned char *id, SilcIdType type)
+{
+
+ switch(type) {
+ case SILC_ID_SERVER:
+ {
+ SilcServerID *server_id = silc_calloc(1, sizeof(*server_id));
+ SILC_GET32_MSB(server_id->ip.s_addr, id);
+ SILC_GET16_MSB(server_id->port, &id[4]);
+ SILC_GET16_MSB(server_id->rnd, &id[6]);
+ return server_id;
+ }
+ break;
+ case SILC_ID_CLIENT:
+ {
+ SilcClientID *client_id = silc_calloc(1, sizeof(*client_id));
+ SILC_GET32_MSB(client_id->ip.s_addr, id);
+ client_id->rnd = id[4];
+ memcpy(client_id->hash, &id[5], CLIENTID_HASH_LEN);
+ return client_id;
+ }
+ break;
+ case SILC_ID_CHANNEL:
+ {
+ SilcChannelID *channel_id = silc_calloc(1, sizeof(*channel_id));
+ SILC_GET32_MSB(channel_id->ip.s_addr, id);
+ SILC_GET16_MSB(channel_id->port, &id[4]);
+ SILC_GET16_MSB(channel_id->rnd, &id[6]);
+ return channel_id;
+ }
+ break;
+ }
+
+ return NULL;
+}
+
+/* Returns length of the ID */
+
+unsigned int silc_id_get_len(SilcIdType type)
+{
+ switch(type) {
+ case SILC_ID_SERVER:
+ return SILC_ID_SERVER_LEN;
+ break;
+ case SILC_ID_CLIENT:
+ return SILC_ID_CLIENT_LEN;
+ break;
+ case SILC_ID_CHANNEL:
+ return SILC_ID_CHANNEL_LEN;
+ break;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+
+ id.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/* These are important ID types used in SILC. SILC server creates these
+ but SILC client has to handle these as well since these are used in
+ packet sending and reception. However, client never creates these
+ but it receives the correct ID's from server. Clients, servers and
+ channels are identified by the these ID's.
+
+ Note that these are currently IPv4 specific, although adding IPv6
+ support is not a bad task and SILC protocol already supports IPv6.
+*/
+
+#ifndef ID_H
+#define ID_H
+
+#define SILC_ID_SERVER_LEN (64 / 8)
+#define SILC_ID_CLIENT_LEN (128 / 8)
+#define SILC_ID_CHANNEL_LEN (64 / 8)
+#define CLIENTID_HASH_LEN (88 / 8) /* Client ID's 88 bit MD5 hash */
+
+/* SILC ID Types */
+#define SILC_ID_NONE 0
+#define SILC_ID_SERVER 1
+#define SILC_ID_CLIENT 2
+#define SILC_ID_CHANNEL 3
+
+/* Type definition for the ID types. */
+typedef unsigned char SilcIdType;
+
+/*
+ 64 bit SilcServerID structure:
+
+ 32 bit IP address
+ 16 bit port
+ 16 bit random number
+*/
+typedef struct {
+ struct in_addr ip; /* 32 bit IP */
+ unsigned short port; /* 16 bit port */
+ unsigned short rnd; /* 16 bit random number */
+} SilcServerID;
+
+/*
+ 128 bit SilcClientID structure:
+
+ 32 bit ServerID IP address [bits 1-32]
+ 8 bit random number
+ 88 bit hash value from nickname
+*/
+typedef struct {
+ struct in_addr ip; /* 32 bit IP */
+ unsigned char rnd; /* 8 bit random number */
+ unsigned char hash[CLIENTID_HASH_LEN]; /* 88 bit MD5 hash */
+} SilcClientID;
+
+/*
+ 64 bit SilcChannel ID structure:
+
+ 32 bit Router's ServerID IP address [bits 1-32]
+ 16 bit Router's ServerID port [bits 33-48]
+ 16 bit random number
+*/
+typedef struct {
+ struct in_addr ip; /* 32 bit IP */
+ unsigned short port; /* 16 bit port */
+ unsigned short rnd; /* 16 bit random number */
+} SilcChannelID;
+
+/* Macros */
+
+/* Compares two ID's */
+#define SILC_ID_COMPARE(id1, id2, len) (memcmp(id1, id2, len))
+
+/* Compares Channel ID's */
+#define SILC_ID_CHANNEL_COMPARE(id1, id2) \
+ SILC_ID_COMPARE(id1, id2, SILC_ID_CHANNEL_LEN)
+
+/* Compares Client ID's */
+#define SILC_ID_CLIENT_COMPARE(id1, id2) \
+ SILC_ID_COMPARE(id1, id2, SILC_ID_CLIENT_LEN)
+
+/* Compares Server ID's */
+#define SILC_ID_SERVER_COMPARE(id1, id2) \
+ SILC_ID_COMPARE(id1, id2, SILC_ID_SERVER_LEN)
+
+/* Compares IP addresses from the ID's. */
+#define SILC_ID_COMPARE_IP(id1, id2) \
+ SILC_ID_COMPARE(id1, id2, 4)
+
+/* Compare nickname hash from Client ID */
+#define SILC_ID_COMPARE_HASH(id, hash) \
+ memcmp(id->hash, hash, CLIENTID_HASH_LEN)
+
+/* Prototypes */
+unsigned char *silc_id_id2str(void *id, SilcIdType type);
+void *silc_id_str2id(unsigned char *id, SilcIdType type);
+unsigned int silc_id_get_len(SilcIdType type);
+
+#endif
--- /dev/null
+/*
+
+ idcache.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/* XXX: This ID cache system sucks and must be rewritten! */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* qsort() sorter function. */
+
+static int silc_idcache_sorter(const void *a, const void *b)
+{
+ SilcIDCache *a1, *b1;
+
+ a1 = (SilcIDCache *)a;
+ b1 = (SilcIDCache *)b;
+
+ return a1->data[0] - b1->data[0];
+}
+
+/* Sorts given cache by data */
+
+void silc_idcache_sort_by_data(SilcIDCache *cache, unsigned int count)
+{
+ qsort(cache, count, sizeof(*cache), silc_idcache_sorter);
+}
+
+/* Find ID Cache entry by data. The data maybe anything that must
+ match exactly. */
+
+int silc_idcache_find_by_data(SilcIDCache *cache, unsigned int cache_count,
+ char *data, SilcIDCache **ret)
+{
+ int i;
+
+ if (cache == NULL)
+ return FALSE;
+
+ if (data == NULL)
+ return FALSE;
+
+ for (i = 0; i < cache_count; i++)
+ if (cache[i].data && !memcmp(cache[i].data, data, strlen(data))) {
+ if (ret)
+ *ret = &(cache[i]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Find ID Cache entry by ID. */
+
+int silc_idcache_find_by_id(SilcIDCache *cache, unsigned int cache_count,
+ void *id, SilcIdType type, SilcIDCache **ret)
+{
+ int i, id_len;
+
+ if (cache == NULL)
+ return FALSE;
+
+ if (id == NULL)
+ return FALSE;
+
+ id_len = silc_id_get_len(type);
+
+ for (i = 0; i < cache_count; i++)
+ if (cache[i].id && !memcmp(cache[i].id, id, id_len)) {
+ if (ret)
+ *ret = &(cache[i]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Add new entry to the cache. Returns number of allocated cache
+ entries in the cache. */
+
+int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
+ char *data, SilcIdType id_type, void *id,
+ void *context)
+{
+ SilcIDCache *c;
+ int i;
+ unsigned long curtime = time(NULL);
+
+ SILC_LOG_DEBUG(("Adding cache entry"));
+
+ c = *cache;
+
+ if (c == NULL) {
+ c = silc_calloc(5, sizeof(*c));
+ if (!c)
+ return 0;
+ cache_count = 5;
+ }
+
+ /* See if it exists already */
+ if (silc_idcache_find_by_id(c, cache_count, id, id_type, NULL) == TRUE)
+ return cache_count;
+
+ for (i = 0; i < cache_count; i++) {
+ if (c[i].data == NULL) {
+ c[i].data = data;
+ c[i].type = id_type;
+ c[i].id = id;
+ c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
+ c[i].context = context;
+ break;
+ }
+ }
+
+ if (i == cache_count) {
+ c = silc_realloc(c, sizeof(*c) * (cache_count + 5));
+ if (!c)
+ return cache_count;
+ for (i = cache_count; i < cache_count + 5; i++) {
+ c[i].data = NULL;
+ c[i].id = NULL;
+ }
+ c[cache_count].data = data;
+ c[cache_count].type = id_type;
+ c[cache_count].id = id;
+ c[cache_count].expire = curtime + SILC_ID_CACHE_EXPIRE;
+ c[cache_count].context = context;
+ cache_count += 5;
+ }
+
+ *cache = c;
+
+ return cache_count;
+}
+
+/* Delete cache entry from cache. */
+/* XXX */
+
+int silc_idcache_del(SilcIDCache *cache, SilcIDCache *old)
+{
+
+ return TRUE;
+}
+
+/* XXX */
+
+int silc_idcache_del_by_data(SilcIDCache *cache, unsigned int cache_count,
+ char *data)
+{
+
+ return TRUE;
+}
+
+/* Deletes ID cache entry by ID. */
+
+int silc_idcache_del_by_id(SilcIDCache *cache, unsigned int cache_count,
+ SilcIdType type, void *id)
+{
+ int i, id_len;
+
+ if (cache == NULL)
+ return FALSE;
+
+ if (id == NULL)
+ return FALSE;
+
+ id_len = silc_id_get_len(type);
+
+ for (i = 0; i < cache_count; i++)
+ if (cache[i].id && !memcmp(cache[i].id, id, id_len)) {
+ cache[i].id = NULL;
+ cache[i].data = NULL;
+ cache[i].type = 0;
+ cache[i].context = NULL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Deletes all ID entries from cache. Free's memory as well. */
+
+int silc_idcache_del_all(SilcIDCache **cache, unsigned int cache_count)
+{
+ SilcIDCache *c = *cache;
+ int i;
+
+ if (c == NULL)
+ return FALSE;
+
+ for (i = 0; i < cache_count; i++) {
+ c[i].id = NULL;
+ c[i].data = NULL;
+ c[i].type = 0;
+ c[i].expire = 0;
+ c[i].context = NULL;
+ }
+
+ silc_free(*cache);
+ *cache = NULL;
+
+ return TRUE;
+}
+
+/* Purges the cache by removing expired cache entires. This does not
+ free any memory though. */
+
+int silc_idcache_purge(SilcIDCache *cache, unsigned int cache_count)
+{
+ unsigned long curtime = time(NULL);
+ int i;
+
+ if (cache == NULL)
+ return FALSE;
+
+ for (i = 0; i < cache_count; i++) {
+ if (cache[i].data &&
+ (cache[i].expire == 0 || cache[i].expire < curtime)) {
+ cache[i].id = NULL;
+ cache[i].data = NULL;
+ cache[i].type = 0;
+ cache[i].expire = 0;
+ cache[i].context = NULL;
+ }
+ }
+
+ return TRUE;
+}
--- /dev/null
+/*
+
+ idcache.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef IDCACHE_H
+#define IDCACHE_H
+
+/*
+ SilcIDCache structure.
+
+ char *data
+
+ The data that is usually used to find the data from the cache.
+ For example for Client ID's this is nickname.
+
+ SilcIdType type
+
+ Type of the ID.
+
+ void *id
+
+ The actual ID.
+
+ unsigned long expire
+
+ Time when this cache entry expires. This is normal time() value
+ plus the validity. Cache entry has expired if current time is
+ more than value in this field, or if this field has been set to
+ zero (0) value.
+
+ void *context
+
+ Any caller specified context.
+
+*/
+typedef struct {
+ char *data;
+ SilcIdType type;
+ void *id;
+ unsigned long expire;
+ void *context;
+} SilcIDCache;
+
+#define SILC_ID_CACHE_EXPIRE 3600
+
+/* Prototypes */
+void silc_idcache_sort_by_data(SilcIDCache *cache, unsigned int count);
+int silc_idcache_find_by_data(SilcIDCache *cache, unsigned int cache_count,
+ char *data, SilcIDCache **ret);
+int silc_idcache_find_by_id(SilcIDCache *cache, unsigned int cache_count,
+ void *id, SilcIdType type, SilcIDCache **ret);
+int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
+ char *data, SilcIdType id_type, void *id,
+ void *context);
+int silc_idcache_del(SilcIDCache *cache, SilcIDCache *old);
+int silc_idcache_del_by_data(SilcIDCache *cache, unsigned int cache_count,
+ char *data);
+int silc_idcache_del_by_id(SilcIDCache *cache, unsigned int cache_count,
+ SilcIdType type, void *id);
+int silc_idcache_del_all(SilcIDCache **cache, unsigned int cache_count);
+int silc_idcache_purge(SilcIDCache *cache, unsigned int cache_count);
+
+#endif
--- /dev/null
+/*
+
+ silcbuffer.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1998 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcbuffer.h"
+
+static unsigned char *silc_buffer_pull_i(SilcBuffer sb, unsigned int len)
+{
+ return silc_buffer_pull(sb, len);
+}
+
+static unsigned char *silc_buffer_push_i(SilcBuffer sb, unsigned int len)
+{
+ return silc_buffer_push(sb, len);
+}
+
+static unsigned char *silc_buffer_pull_tail_i(SilcBuffer sb, unsigned int len)
+{
+ return silc_buffer_pull_tail(sb, len);
+}
+
+static unsigned char *silc_buffer_push_tail_i(SilcBuffer sb, unsigned int len)
+{
+ return silc_buffer_push_tail(sb, len);
+}
+
+static unsigned char *silc_buffer_put_head_i(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ return silc_buffer_put_head(sb, data, len);
+}
+
+static unsigned char *silc_buffer_put_i(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ return silc_buffer_put(sb, data, len);
+}
+
+static unsigned char *silc_buffer_put_tail_i(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ return silc_buffer_put_tail(sb, data, len);
+}
+
+/* Allocates a new SilcBuffer and returns a pointer to it. The data
+ area of the new buffer is set to the real beginning of the buffer.
+
+ Buffer after allocation:
+ ---------------------------------
+ | |
+ ---------------------------------
+ ^ head, data, tail ^ end
+
+*/
+
+SilcBuffer silc_buffer_alloc(unsigned int len)
+{
+ SilcBuffer sb;
+ unsigned char *data;
+
+ /* Allocate new SilcBuffer */
+ sb = silc_calloc(1, sizeof(*sb));
+ if (!sb)
+ return NULL;
+
+ /* Allocate the actual data area */
+ data = silc_malloc(len);
+ if (!data)
+ return NULL;
+ memset(data, 0, len);
+
+ /* Set pointers to the new buffer */
+ sb->truelen = len;
+ sb->len = 0;
+ sb->head = data;
+ sb->data = data;
+ sb->tail = data;
+ sb->end = data + sb->truelen;
+
+ /* Set the function pointers */
+ sb->pull = silc_buffer_pull_i;
+ sb->push = silc_buffer_push_i;
+ sb->pull_tail = silc_buffer_pull_tail_i;
+ sb->push_tail = silc_buffer_push_tail_i;
+ sb->put = silc_buffer_put_i;
+ sb->put_head = silc_buffer_put_head_i;
+ sb->put_tail = silc_buffer_put_tail_i;
+
+ return sb;
+}
+
+/* Free's a SilcBuffer */
+
+void silc_buffer_free(SilcBuffer sb)
+{
+ if (sb) {
+ memset(sb->head, 'F', sb->truelen);
+ silc_free(sb->head);
+ silc_free(sb);
+ }
+}
+
+#ifdef SILC_DEBUG /* If we are doing debugging we won't
+ have the optimized inline buffer functions
+ available as optimization is not set
+ to compiler. These normal routines are
+ used in debugging mode. */
+
+/* XXX These are currenly obsolte as SILC is compiled always with -O
+ flag thus inline functions maybe used. So, fix these. */
+
+/* Pulls current data area towards end. The length of the currently
+ valid data area is also decremented. Returns pointer to the data
+ area before pulling.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pulls the start of the data area.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_data = sb->data;
+
+ assert(len <= (sb->tail - sb->data));
+
+ sb->data += len;
+ sb->len -= len;
+
+ return old_data;
+}
+
+/* Pushes current data area towards beginning. Length of the currently
+ valid data area is also incremented. Returns a pointer to the
+ data area before pushing.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pushes the start of the data area.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_data = sb->data;
+
+ assert((sb->data - len) >= sb->head);
+
+ sb->data -= len;
+ sb->len += len;
+
+ return old_data;
+}
+
+/* Pulls current tail section towards end. Length of the current valid
+ data area is also incremented. Returns a pointer to the data area
+ before pulling.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pulls the start of the tail section.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_tail = sb->tail;
+
+ assert((sb->end - sb->tail) >= len);
+
+ sb->tail += len;
+ sb->len += len;
+
+ return old_tail;
+}
+
+/* Pushes current tail section towards beginning. Length of the current
+ valid data area is also decremented. Returns a pointer to the
+ tail section before pushing.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pushes the start of the tail section.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_tail = sb->tail;
+
+ assert((sb->tail - len) >= sb->data);
+
+ sb->tail -= len;
+ sb->len -= len;
+
+ return old_tail;
+}
+
+/* Puts data at the head of the buffer. Returns pointer to the copied
+ data area.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Puts data to the head section.
+*/
+
+unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ assert((sb->data - sb->head) >= len);
+ return memcpy(sb->head, data, len);
+}
+
+/* Puts data at the start of the valid data area. Returns a pointer
+ to the copied data area.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Puts data to the data section.
+*/
+
+unsigned char *silc_buffer_put(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ assert((sb->tail - sb->data) >= len);
+ return memcpy(sb->data, data, len);
+}
+
+/* Puts data at the tail of the buffer. Returns pointer to the copied
+ data area.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Puts data to the tail section.
+*/
+
+unsigned char *silc_buffer_put_tail(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ assert((sb->end - sb->tail) >= len);
+ return memcpy(sb->tail, data, len);
+}
+
+#endif
--- /dev/null
+/*
+
+ silcbuffer.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1998 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCBUFFER_H
+#define SILCBUFFER_H
+
+/*
+ SILC Buffer object.
+
+ SilcBuffer is very simple and easy to use, yet you can do to the
+ buffer almost anything you want with its method functions. The buffer
+ is constructed of four different data sections that in whole creates
+ the allocated data area. Following short description of the fields
+ of the buffer.
+
+ unsigned int truelen;
+
+ True length of the buffer. This is set at the allocation of the
+ buffer and it should not be touched after that. This field should
+ be considered read-only.
+
+ unsigned int len;
+
+ Length of the currently valid data area. Tells the length of the
+ data at the buffer. This is set to zero at the allocation of the
+ buffer and should not be updated by hand. Method functions of the
+ buffer automatically updates this field. However, it is not
+ read-only field and can be updated manually if necessary.
+
+ unsiged char *head;
+
+ Head of the allocated buffer. This is the start of the allocated
+ data area and remains as same throughout the lifetime of the buffer.
+ However, the end of the head area or the start of the currently valid
+ data area is variable.
+
+ --------------------------------
+ | head | data | tail |
+ --------------------------------
+ ^ ^
+
+ Current head section in the buffer is sb->data - sb->head.
+
+ unsigned char *data;
+
+ Currently valid data area. This is the start of the currently valid
+ main data area. The data area is variable in all directions.
+
+ --------------------------------
+ | head | data | tail |
+ --------------------------------
+ ^ ^
+
+ Current valid data area in the buffer is sb->tail - sb->data.
+
+ unsigned char *tail;
+
+ Tail of the buffer. This is the end of the currently valid data area
+ or start of the tail area. The start of the tail area is variable.
+
+ --------------------------------
+ | head | data | tail |
+ --------------------------------
+ ^ ^
+
+ Current tail section in the buffer is sb->end - sb->tail.
+
+ unsigned char *end;
+
+ End of the allocated buffer. This is the end of the allocated data
+ area and remains as same throughout the lifetime of the buffer.
+ Usually this field is not needed except when checking the size
+ of the buffer.
+
+ --------------------------------
+ | head | data | tail |
+ --------------------------------
+ ^
+
+ Length of the entire buffer is (ie. truelen) sb->end - sb->head.
+
+ Currently valid data area is considered to be the main data area in
+ the buffer. However, the entire buffer is of course valid data and can
+ be used as such. Usually head section of the buffer includes different
+ kind of headers or similiar. Data section includes the main data of
+ the buffer. Tail section can be seen as a reserve space of the data
+ section. Tail section can be pulled towards end thus the data section
+ becomes larger.
+
+ This buffer scheme is based on Linux kernel's Socket Buffer, the
+ idea were taken directly from there and credits should go there.
+
+*/
+
+typedef struct SilcBufferStruct {
+ unsigned int truelen;
+ unsigned int len;
+ unsigned char *head;
+ unsigned char *data;
+ unsigned char *tail;
+ unsigned char *end;
+
+ /* Method functions. */
+ unsigned char *(*pull)(struct SilcBufferStruct *, unsigned int);
+ unsigned char *(*push)(struct SilcBufferStruct *, unsigned int);
+ unsigned char *(*pull_tail)(struct SilcBufferStruct *, unsigned int);
+ unsigned char *(*push_tail)(struct SilcBufferStruct *, unsigned int);
+ unsigned char *(*put)(struct SilcBufferStruct *, unsigned char *,
+ unsigned int);
+ unsigned char *(*put_head)(struct SilcBufferStruct *, unsigned char *,
+ unsigned int);
+ unsigned char *(*put_tail)(struct SilcBufferStruct *, unsigned char *,
+ unsigned int);
+} SilcBufferObject;
+
+typedef SilcBufferObject *SilcBuffer;
+
+/* Macros */
+
+/* Returns the true length of the buffer. This is used to pull
+ the buffer area to the end of the buffer. */
+#define SILC_BUFFER_END(x) ((x)->end - (x)->head)
+
+#ifndef SILC_DEBUG /* When we are not doing debugging we use
+ optimized inline buffer functions. */
+/*
+ * Optimized buffer managing routines. These are short inline
+ * functions.
+ */
+
+/* Pulls current data area towards end. The length of the currently
+ valid data area is also decremented. Returns pointer to the data
+ area before pulling.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pulls the start of the data area.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+extern inline
+unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_data = sb->data;
+
+ assert(len <= (sb->tail - sb->data));
+
+ sb->data += len;
+ sb->len -= len;
+
+ return old_data;
+}
+
+/* Pushes current data area towards beginning. Length of the currently
+ valid data area is also incremented. Returns a pointer to the
+ data area before pushing.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pushes the start of the data area.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+extern inline
+unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_data = sb->data;
+
+ assert((sb->data - len) >= sb->head);
+
+ sb->data -= len;
+ sb->len += len;
+
+ return old_data;
+}
+
+/* Pulls current tail section towards end. Length of the current valid
+ data area is also incremented. Returns a pointer to the data area
+ before pulling.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pulls the start of the tail section.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+extern inline
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_tail = sb->tail;
+
+ assert((sb->end - sb->tail) >= len);
+
+ sb->tail += len;
+ sb->len += len;
+
+ return old_tail;
+}
+
+/* Pushes current tail section towards beginning. Length of the current
+ valid data area is also decremented. Returns a pointer to the
+ tail section before pushing.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Pushes the start of the tail section.
+
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+*/
+
+extern inline
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len)
+{
+ unsigned char *old_tail = sb->tail;
+
+ assert((sb->tail - len) >= sb->data);
+
+ sb->tail -= len;
+ sb->len -= len;
+
+ return old_tail;
+}
+
+/* Puts data at the head of the buffer. Returns pointer to the copied
+ data area.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Puts data to the head section.
+*/
+
+extern inline
+unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ assert((sb->data - sb->head) >= len);
+ return memcpy(sb->head, data, len);
+}
+
+/* Puts data at the start of the valid data area. Returns a pointer
+ to the copied data area.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Puts data to the data section.
+*/
+
+extern inline
+unsigned char *silc_buffer_put(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ assert((sb->tail - sb->data) >= len);
+ return memcpy(sb->data, data, len);
+}
+
+/* Puts data at the tail of the buffer. Returns pointer to the copied
+ data area.
+
+ Example:
+ ---------------------------------
+ | head | data | tail |
+ ---------------------------------
+ ^
+ Puts data to the tail section.
+*/
+
+extern inline
+unsigned char *silc_buffer_put_tail(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len)
+{
+ assert((sb->end - sb->tail) >= len);
+ return memcpy(sb->tail, data, len);
+}
+
+#endif /* !SILC_DEBUG */
+
+/* Prototypes */
+SilcBuffer silc_buffer_alloc(unsigned int len);
+void silc_buffer_free(SilcBuffer sb);
+#ifdef SILC_DEBUG
+unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len);
+unsigned char *silc_buffer_put(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len);
+unsigned char *silc_buffer_put_tail(SilcBuffer sb,
+ unsigned char *data,
+ unsigned int len);
+#endif
+
+#endif
--- /dev/null
+/*
+
+ silcbuffmt.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/* XXX: These routines needs to be made more stable as these can crash
+ if the data (for unformatting for example) is malformed or the buffer
+ is too short. Must be fixed. There are some other obvious bugs as
+ well. */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Formats the arguments sent and puts them into the buffer sent as
+ argument. The buffer must be initialized beforehand and it must have
+ enough free space to include the formatted data. If this function
+ fails caller should not trust the buffer anymore and should free it.
+ This function is used, for example, to create packets to send over
+ network. */
+
+int silc_buffer_format(SilcBuffer dst, ...)
+{
+ va_list ap;
+ SilcBufferParamType fmt;
+ unsigned char *start_ptr = dst->data;
+
+ va_start(ap, dst);
+
+ /* Parse the arguments by formatting type. */
+ while(1) {
+ fmt = va_arg(ap, SilcBufferParamType);
+
+ switch(fmt) {
+ case SILC_BUFFER_PARAM_SI8_CHAR:
+ {
+ char x = va_arg(ap, char);
+ silc_buffer_put(dst, &x, 1);
+ silc_buffer_pull(dst, 1);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI8_CHAR:
+ {
+ unsigned char x = va_arg(ap, unsigned char);
+ silc_buffer_put(dst, &x, 1);
+ silc_buffer_pull(dst, 1);
+ break;
+ }
+ case SILC_BUFFER_PARAM_SI16_SHORT:
+ {
+ unsigned char xf[2];
+ short x = va_arg(ap, short);
+ SILC_PUT16_MSB(x, xf);
+ silc_buffer_put(dst, xf, 2);
+ silc_buffer_pull(dst, 2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_SHORT:
+ {
+ unsigned char xf[2];
+ unsigned short x = va_arg(ap, unsigned short);
+ SILC_PUT16_MSB(x, xf);
+ silc_buffer_put(dst, xf, 2);
+ silc_buffer_pull(dst, 2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_SI32_INT:
+ {
+ unsigned char xf[4];
+ int x = va_arg(ap, int);
+ SILC_PUT32_MSB(x, xf);
+ silc_buffer_put(dst, xf, 4);
+ silc_buffer_pull(dst, 4);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI32_INT:
+ {
+ unsigned char xf[4];
+ unsigned int x = va_arg(ap, unsigned int);
+ SILC_PUT32_MSB(x, xf);
+ silc_buffer_put(dst, xf, 4);
+ silc_buffer_pull(dst, 4);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_STRING:
+ case SILC_BUFFER_PARAM_UI32_STRING:
+ case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
+ {
+ unsigned char *x = va_arg(ap, unsigned char *);
+ silc_buffer_put(dst, x, strlen(x));
+ silc_buffer_pull(dst, strlen(x));
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_NSTRING:
+ case SILC_BUFFER_PARAM_UI32_NSTRING:
+ case SILC_BUFFER_PARAM_UI_XNSTRING:
+ case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
+ {
+ unsigned char *x = va_arg(ap, unsigned char *);
+ unsigned int len = va_arg(ap, unsigned int);
+ silc_buffer_put(dst, x, len);
+ silc_buffer_pull(dst, len);
+ break;
+ }
+ case SILC_BUFFER_PARAM_END:
+ goto ok;
+ break;
+ default:
+ SILC_LOG_ERROR(("Bad buffer formatting type `%d'. Could not "
+ "format the data.", fmt));
+ goto fail;
+ break;
+ }
+ }
+
+ fail:
+ SILC_LOG_ERROR(("Error occured while formatting data"));
+ return FALSE;
+
+ ok:
+ /* Push the buffer back to where it belongs. */
+ silc_buffer_push(dst, dst->data - start_ptr);
+ return dst->len;
+}
+
+/* Unformats the buffer sent as argument. The unformatted data is returned
+ to the variable argument list of pointers. The buffer must point to the
+ start of the data area to be unformatted. Buffer maybe be safely free'd
+ after this returns succesfully. */
+
+int silc_buffer_unformat(SilcBuffer src, ...)
+{
+ va_list ap;
+ SilcBufferParamType fmt;
+ unsigned char *start_ptr = src->data;
+ int len = 0;
+
+ va_start(ap, src);
+
+ /* Parse the arguments by formatting type. */
+ while(1) {
+ fmt = va_arg(ap, SilcBufferParamType);
+
+ switch(fmt) {
+ case SILC_BUFFER_PARAM_SI8_CHAR:
+ {
+ char *x = va_arg(ap, char *);
+ if (x)
+ *x = src->data[0];
+ silc_buffer_pull(src, 1);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI8_CHAR:
+ {
+ unsigned char *x = va_arg(ap, unsigned char *);
+ if (x)
+ *x = src->data[0];
+ silc_buffer_pull(src, 1);
+ break;
+ }
+ case SILC_BUFFER_PARAM_SI16_SHORT:
+ {
+ short *x = va_arg(ap, short *);
+ if (x)
+ SILC_GET16_MSB(*x, src->data);
+ silc_buffer_pull(src, 2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_SHORT:
+ {
+ unsigned short *x = va_arg(ap, unsigned short *);
+ if (x)
+ SILC_GET16_MSB(*x, src->data);
+ silc_buffer_pull(src, 2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_SI32_INT:
+ {
+ int *x = va_arg(ap, int *);
+ if (x)
+ SILC_GET32_MSB(*x, src->data);
+ silc_buffer_pull(src, 4);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI32_INT:
+ {
+ unsigned int *x = va_arg(ap, unsigned int *);
+ if (x)
+ SILC_GET32_MSB(*x, src->data);
+ silc_buffer_pull(src, 4);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_STRING:
+ {
+ unsigned short len2;
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SILC_GET16_MSB(len2, src->data);
+ silc_buffer_pull(src, 2);
+ if ((len2 > src->len))
+ goto fail;
+ if (len2 < 1)
+ break;
+ if (x)
+ memcpy(x, src->data, len2);
+ silc_buffer_pull(src, len2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
+ {
+ unsigned short len2;
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SILC_GET16_MSB(len2, src->data);
+ silc_buffer_pull(src, 2);
+ if ((len2 > src->len))
+ goto fail;
+ if (len2 < 1)
+ break;
+ if (x) {
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
+ memcpy(*x, src->data, len2);
+ }
+ silc_buffer_pull(src, len2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI32_STRING:
+ {
+ unsigned int len2;
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SILC_GET32_MSB(len2, src->data);
+ silc_buffer_pull(src, 4);
+ if ((len2 > src->len))
+ goto fail;
+ if (len2 < 1)
+ break;
+ if (x)
+ memcpy(x, src->data, len2);
+ silc_buffer_pull(src, len2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
+ {
+ unsigned int len2;
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SILC_GET32_MSB(len2, src->data);
+ silc_buffer_pull(src, 4);
+ if ((len2 > src->len))
+ goto fail;
+ if (len2 < 1)
+ break;
+ if (x) {
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
+ memcpy(*x, src->data, len2);
+ }
+ silc_buffer_pull(src, len2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_NSTRING:
+ {
+ unsigned short len2;
+ unsigned char **x = va_arg(ap, unsigned char **);
+ unsigned short *len = va_arg(ap, unsigned short *);
+ SILC_GET16_MSB(len2, src->data);
+ silc_buffer_pull(src, 2);
+ if ((len2 > src->len))
+ break;
+ if (len2 < 1)
+ break;
+ if (len)
+ *len = len2;
+ if (x)
+ memcpy(x, src->data, len2);
+ silc_buffer_pull(src, len2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
+ {
+ unsigned short len2;
+ unsigned char **x = va_arg(ap, unsigned char **);
+ unsigned short *len = va_arg(ap, unsigned short *);
+ SILC_GET16_MSB(len2, src->data);
+ silc_buffer_pull(src, 2);
+ if ((len2 > src->len))
+ break;
+ if (len2 < 1)
+ break;
+ if (len)
+ *len = len2;
+ if (x) {
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
+ memcpy(*x, src->data, len2);
+ }
+ silc_buffer_pull(src, len2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI32_NSTRING:
+ {
+ unsigned int len2;
+ unsigned char **x = va_arg(ap, unsigned char **);
+ unsigned int *len = va_arg(ap, unsigned int *);
+ SILC_GET32_MSB(len2, src->data);
+ silc_buffer_pull(src, 4);
+ if ((len2 > src->len))
+ goto fail;
+ if (len2 < 1)
+ break;
+ if (len)
+ *len = len2;
+ if (x)
+ memcpy(x, src->data, len2);
+ silc_buffer_pull(src, len2);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
+ {
+ unsigned char **x = va_arg(ap, unsigned char **);
+ unsigned int len = va_arg(ap, unsigned int);
+ if (len && x) {
+ *x = silc_calloc(len + 1, sizeof(unsigned char));
+ memcpy(*x, src->data, len);
+ }
+ silc_buffer_pull(src, len);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI_XNSTRING:
+ {
+ unsigned char **x = va_arg(ap, unsigned char **);
+ unsigned int len = va_arg(ap, unsigned int);
+ if (len && x)
+ memcpy(x, src->data, len);
+ silc_buffer_pull(src, len);
+ break;
+ }
+ case SILC_BUFFER_PARAM_END:
+ goto ok;
+ break;
+ default:
+ SILC_LOG_ERROR(("Bad buffer formatting type `%d'. Could not "
+ "format the data.", fmt));
+ goto fail;
+ break;
+ }
+ }
+
+ fail:
+ SILC_LOG_ERROR(("Error occured while unformatting buffer"));
+ return FALSE;
+
+ ok:
+ /* Push the buffer back to the start. */
+ len = src->data - start_ptr;
+ silc_buffer_push(src, len);
+ return len;
+}
--- /dev/null
+/*
+
+ silcbuffmt.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCBUFFMT_H
+#define SILCBUFFMT_H
+
+/* Buffer parameter types.
+
+ _SI_ = signed
+ _UI_ = unsigned
+
+*/
+typedef enum {
+ SILC_BUFFER_PARAM_SI8_CHAR,
+ SILC_BUFFER_PARAM_UI8_CHAR,
+
+ SILC_BUFFER_PARAM_SI16_SHORT,
+ SILC_BUFFER_PARAM_UI16_SHORT,
+
+ SILC_BUFFER_PARAM_SI32_INT,
+ SILC_BUFFER_PARAM_UI32_INT,
+
+ SILC_BUFFER_PARAM_UI16_STRING,
+ SILC_BUFFER_PARAM_UI16_STRING_ALLOC,
+ SILC_BUFFER_PARAM_UI32_STRING,
+ SILC_BUFFER_PARAM_UI32_STRING_ALLOC,
+ SILC_BUFFER_PARAM_UI16_NSTRING,
+ SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC,
+ SILC_BUFFER_PARAM_UI32_NSTRING,
+ SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC,
+ SILC_BUFFER_PARAM_UI_XNSTRING,
+ SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC,
+
+ SILC_BUFFER_PARAM_END
+} SilcBufferParamType;
+
+/* Macros for expanding parameters into variable function argument list.
+ These are passed to silc_buffer_format and silc_buffer_unformat
+ functions. */
+
+/* One signed/unsigned character.
+
+ Formatting: SILC_STR_SI_CHAR(char)
+ SILC_STR_UI_CHAR(unsigned char)
+ Unformatting: SILC_STR_SI_CHAR(char *)
+ SILC_STR_UI_CHAR(unsigned char *)
+
+*/
+#define SILC_STR_SI_CHAR(x) SILC_BUFFER_PARAM_SI8_CHAR, (x)
+#define SILC_STR_UI_CHAR(x) SILC_BUFFER_PARAM_UI8_CHAR, (x)
+
+/* Signed/unsigned short.
+
+ Formatting: SILC_STR_SI_SHORT(short)
+ SILC_STR_UI_SHORT(unsigned short)
+ Unformatting: SILC_STR_SI_SHORT(short *)
+ SILC_STR_UI_SHORT(unsigned short *)
+
+*/
+#define SILC_STR_SI_SHORT(x) SILC_BUFFER_PARAM_SI16_SHORT, (x)
+#define SILC_STR_UI_SHORT(x) SILC_BUFFER_PARAM_UI16_SHORT, (x)
+
+/* Signed/unsigned int.
+
+ Formatting: SILC_STR_SI_INT(int)
+ SILC_STR_UI_INT(unsigned int)
+ Unformatting: SILC_STR_SI_INT(int *)
+ SILC_STR_UI_INT(unsigned int *)
+
+*/
+#define SILC_STR_SI_INT(x) SILC_BUFFER_PARAM_SI32_INT, (x)
+#define SILC_STR_UI_INT(x) SILC_BUFFER_PARAM_UI32_INT, (x)
+
+/* Unsigned NULL terminated string. Note that the string must be
+ NULL terminated because strlen() will be used to get the length of
+ the string.
+
+ Formatting: SILC_STR_UI32_STRING(unsigned char *)
+ Unformatting: SILC_STR_UI32_STRING(unsigned char **)
+
+ Unformatting procedure will check for length of the string from the
+ buffer before trying to get the string out. Thus, one *must* format the
+ length as UI_INT or UI_SHORT into the buffer *before* formatting the
+ actual string to the buffer, and, in unformatting one must ignore the
+ length of the string because unformatting procedure will take it
+ automatically.
+
+ Example:
+
+ Formatting: ..., SILC_STR_UI_INT(strlen(string)),
+ SILC_STR_UI32_STRING(string), ...
+ Unformatting: ..., SILC_STR_UI32_STRING(&string), ...
+
+ I.e., you ignore the formatted length field in unformatting. If you don't
+ the unformatting procedure might fail and it definitely does not unformat
+ the data reliably.
+
+ _ALLOC routines automatically allocates memory for the variable sent
+ as argument in unformatting.
+
+*/
+#define SILC_STR_UI16_STRING(x) SILC_BUFFER_PARAM_UI16_STRING, (x)
+#define SILC_STR_UI16_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI16_STRING_ALLOC, (x)
+#define SILC_STR_UI32_STRING(x) SILC_BUFFER_PARAM_UI32_STRING, (x)
+#define SILC_STR_UI32_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI32_STRING_ALLOC, (x)
+
+/* Unsigned string. Second argument is the length of the string.
+
+ Formatting: SILC_STR_UI32_NSTRING(unsigned char *, unsigned int)
+ Unformatting: SILC_STR_UI32_NSTRING(unsigned char **, unsigned int *)
+
+ Unformatting procedure will check for length of the string from the
+ buffer before trying to get the string out. Thus, one *must* format the
+ length as UI_INT or UI_SHORT into the buffer *before* formatting the
+ actual string to the buffer, and, in unformatting one must ignore the
+ length of the string because unformatting procedure will take it
+ automatically.
+
+ Example:
+
+ Formatting: ..., SILC_STR_UI_INT(strlen(string)),
+ SILC_STR_UI32_NSTRING(string, strlen(string)), ...
+ Unformatting: ..., SILC_STR_UI32_NSTRING(&string, &len), ...
+
+ I.e., you ignore the formatted length field in unformatting. If you don't
+ the unformatting procedure might fail and it definitely does not unformat
+ the data reliably. The length taken from the buffer is returned to the
+ pointer sent as argument (&len in above example).
+
+ UI/SI16 and UI/SI32 means that the length is considered to be either
+ short (16 bits) or int (32 bits) in unformatting.
+
+ _ALLOC routines automatically allocates memory for the variable sent
+ as argument in unformatting.
+
+*/
+#define SILC_STR_UI16_NSTRING(x, l) SILC_BUFFER_PARAM_UI16_NSTRING, (x), (l)
+#define SILC_STR_UI16_NSTRING_ALLOC(x, l) \
+ SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC, (x), (l)
+#define SILC_STR_UI32_NSTRING(x, l) SILC_BUFFER_PARAM_UI32_NSTRING, (x), (l)
+#define SILC_STR_UI32_NSTRING_ALLOC(x, l) \
+ SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC, (x), (l)
+
+/* Extended Unsigned string formatting. Second argument is the length of
+ the string.
+
+ Formatting: This is equal to using *_NSTRING
+ Unformatting: SILC_STR_UI_XNSTRING(unsigned char **, unsigned int)
+
+ This type can be used to take arbitrary length string from the buffer
+ by sending the requested amount of bytes as argument. This differs
+ from *_STRING and *_NSTRING so that this doesn't try to find the
+ length of the data from the buffer but the length of the data is
+ sent as argument. This a handy way to unformat fixed length strings
+ from the buffer without having the length of the string formatted
+ in the buffer.
+
+ _ALLOC routines automatically allocates memory for the variable sent
+ as argument in unformatting.
+
+*/
+#define SILC_STR_UI_XNSTRING(x, l) SILC_BUFFER_PARAM_UI_XNSTRING, (x), (l)
+#define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
+ SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
+
+/* Marks end of the argument list. This must the at the end of the
+ argument list or error will occur. */
+#define SILC_STR_END SILC_BUFFER_PARAM_END
+
+/* Prototypes */
+int silc_buffer_format(SilcBuffer dst, ...);
+int silc_buffer_unformat(SilcBuffer src, ...);
+
+#endif
--- /dev/null
+/*
+
+ silcbufutil.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#ifdef SILC_DEBUG /* If we are doing debugging we won't
+ have the optimized inline buffer functions
+ available as optimization is not set
+ to compiler. These normal routines are
+ used in debugging mode. */
+
+/* Clears and initialiazes the buffer to the state as if it was just
+ allocated by silc_buffer_alloc. */
+
+void silc_buffer_clear(SilcBuffer sb)
+{
+ memset(sb->head, 0, sb->truelen);
+ sb->data = sb->head;
+ sb->tail = sb->head;
+ sb->len = 0;
+}
+
+/* Generates copy of a SilcBuffer. This copies everything inside the
+ currently valid data area, nothing more. Use silc_buffer_clone to
+ copy entire buffer. */
+
+SilcBuffer silc_buffer_copy(SilcBuffer sb)
+{
+ SilcBuffer sb_new;
+
+ sb_new = silc_buffer_alloc(sb->len);
+ silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+ silc_buffer_put(sb_new, sb->data, sb->len);
+
+ return sb_new;
+}
+
+/* Clones SilcBuffer. This generates new SilcBuffer and copies
+ everything from the source buffer. The result is exact clone of
+ the original buffer. */
+
+SilcBuffer silc_buffer_clone(SilcBuffer sb)
+{
+ SilcBuffer sb_new;
+
+ sb_new = silc_buffer_alloc(sb->truelen);
+ silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+ silc_buffer_put(sb_new, sb->head, sb->truelen);
+ sb_new->data = sb_new->head + sb->len;
+ sb_new->tail = sb_new->head + (sb->end - sb->tail);
+ sb_new->len = sb->len;
+
+ return sb_new;
+}
+
+#endif /* SILC_DEBUG */
--- /dev/null
+/*
+
+ silcbufutil.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCBUFUTIL_H
+#define SILCBUFUTIL_H
+
+#ifndef SILC_DEBUG /* When we are not doing debugging we use
+ optimized inline buffer functions. */
+
+/* Clears and initialiazes the buffer to the state as if it was just
+ allocated by silc_buffer_alloc. */
+
+extern inline
+void silc_buffer_clear(SilcBuffer sb)
+{
+ memset(sb->head, 0, sb->truelen);
+ sb->data = sb->head;
+ sb->tail = sb->head;
+ sb->len = 0;
+}
+
+/* Generates copy of a SilcBuffer. This copies everything inside the
+ currently valid data area, nothing more. Use silc_buffer_clone to
+ copy entire buffer. */
+
+extern inline
+SilcBuffer silc_buffer_copy(SilcBuffer sb)
+{
+ SilcBuffer sb_new;
+
+ sb_new = silc_buffer_alloc(sb->len);
+ silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+ silc_buffer_put(sb_new, sb->data, sb->len);
+
+ return sb_new;
+}
+
+/* Clones SilcBuffer. This generates new SilcBuffer and copies
+ everything from the source buffer. The result is exact clone of
+ the original buffer. */
+
+extern inline
+SilcBuffer silc_buffer_clone(SilcBuffer sb)
+{
+ SilcBuffer sb_new;
+
+ sb_new = silc_buffer_alloc(sb->truelen);
+ silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+ silc_buffer_put(sb_new, sb->head, sb->truelen);
+ sb_new->data = sb_new->head + sb->len;
+ sb_new->tail = sb_new->head + (sb->end - sb->tail);
+ sb_new->len = sb->len;
+
+ return sb_new;
+}
+
+#endif /* !SILC_DEBUG */
+
+/* Prototypes */
+#ifdef SILC_DEBUG
+void silc_buffer_clear(SilcBuffer sb);
+SilcBuffer silc_buffer_copy(SilcBuffer sb);
+SilcBuffer silc_buffer_clone(SilcBuffer sb);
+#endif
+
+#endif
--- /dev/null
+/*
+
+ silcchannel.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcchannel.h"
+
+/* Channel Payload structure. Contents of this structure is parsed
+ from SILC packets. */
+struct SilcChannelPayloadStruct {
+ unsigned short nick_len;
+ unsigned char *nick;
+ unsigned short data_len;
+ unsigned char *data;
+ unsigned short iv_len;
+ unsigned char *iv;
+};
+
+/* Channel Key Payload structrue. Channel keys are parsed from SILC
+ packets into this structure. */
+struct SilcChannelKeyPayloadStruct {
+ unsigned short id_len;
+ unsigned char *id;
+ unsigned short cipher_len;
+ unsigned char *cipher;
+ unsigned short key_len;
+ unsigned char *key;
+};
+
+/* Parses channel payload returning new channel payload structure */
+
+SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer)
+{
+ SilcChannelPayload new;
+
+ SILC_LOG_DEBUG(("Parsing channel payload"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new channel payload"));
+ return NULL;
+ }
+
+ /* Parse the Channel Payload. Ignore padding and IV, we don't need
+ them. */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&new->nick, &new->nick_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&new->data, &new->data_len),
+ SILC_STR_UI16_NSTRING_ALLOC(NULL, NULL),
+ SILC_STR_END);
+
+ if (new->data_len < 1) {
+ SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
+ goto err;
+ }
+
+ return new;
+
+ err:
+ if (new->nick)
+ silc_free(new->nick);
+ if (new->data)
+ silc_free(new->data);
+ if (new->iv)
+ silc_free(new->iv);
+ silc_free(new);
+ return NULL;
+}
+
+/* Encodes channel payload into a buffer and returns it. This is used
+ to add channel payload into a packet. As the channel payload is
+ encrypted separately from other parts of the packet padding must
+ be applied to the payload. */
+
+SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
+ unsigned char *nick,
+ unsigned short data_len,
+ unsigned char *data,
+ unsigned short iv_len,
+ unsigned char *iv,
+ SilcRng rng)
+{
+ int i;
+ SilcBuffer buffer;
+ unsigned int len, pad_len;
+ unsigned char pad[SILC_PACKET_MAX_PADLEN];
+
+ SILC_LOG_DEBUG(("Encoding channel payload"));
+
+ /* Calculate length of padding. IV is not included into the calculation
+ since it is not encrypted. */
+ len = 2 + nick_len + 2 + data_len + 2;
+ pad_len = SILC_PACKET_PADLEN((len + 2));
+
+ /* Allocate channel payload buffer */
+ len += pad_len;
+ buffer = silc_buffer_alloc(len + iv_len);
+ if (!buffer)
+ return NULL;
+
+ /* Generate padding */
+ for (i = 0; i < pad_len; i++)
+ pad[i] = silc_rng_get_byte(rng);
+
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+
+ /* Encode the Channel Payload */
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(nick_len),
+ SILC_STR_UI_XNSTRING(nick, nick_len),
+ SILC_STR_UI_SHORT(data_len),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_UI_SHORT(pad_len),
+ SILC_STR_UI_XNSTRING(pad, pad_len),
+ SILC_STR_UI_XNSTRING(iv, iv_len),
+ SILC_STR_END);
+
+ memset(pad, 0, pad_len);
+ return buffer;
+}
+
+/* Free's Channel Payload */
+
+void silc_channel_free_payload(SilcChannelPayload payload)
+{
+ if (payload) {
+ if (payload->data)
+ silc_free(payload->data);
+ if (payload->iv)
+ silc_free(payload->iv);
+ silc_free(payload);
+ }
+}
+
+/* Return nickname */
+
+unsigned char *silc_channel_get_nickname(SilcChannelPayload payload,
+ unsigned int *nick_len)
+{
+ if (nick_len)
+ *nick_len = payload->nick_len;
+
+ return payload->nick;
+}
+
+/* Return data */
+
+unsigned char *silc_channel_get_data(SilcChannelPayload payload,
+ unsigned int *data_len)
+{
+ if (data_len)
+ *data_len = payload->data_len;
+
+ return payload->data;
+}
+
+/* Return initial vector */
+
+unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
+ unsigned int *iv_len)
+{
+ if (iv_len)
+ *iv_len = payload->iv_len;
+
+ return payload->iv;
+}
+
+/* Parses channel key payload returning new channel key payload structure */
+
+SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer)
+{
+ SilcChannelKeyPayload new;
+
+ SILC_LOG_DEBUG(("Parsing channel key payload"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new channel key payload"));
+ return NULL;
+ }
+
+ /* Parse the Channel Key Payload */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
+ &new->cipher_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
+ SILC_STR_END);
+
+ if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
+ SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
+ goto err;
+ }
+
+ return new;
+
+ err:
+ if (new->id)
+ silc_free(new->id);
+ if (new->cipher)
+ silc_free(new->cipher);
+ if (new->key)
+ silc_free(new->key);
+ silc_free(new);
+ return NULL;
+}
+
+/* Encodes channel key payload into a buffer and returns it. This is used
+ to add channel key payload into a packet. */
+
+SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
+ unsigned char *id,
+ unsigned short cipher_len,
+ unsigned char *cipher,
+ unsigned short key_len,
+ unsigned char *key)
+{
+ SilcBuffer buffer;
+ unsigned int len;
+
+ SILC_LOG_DEBUG(("Encoding channel key payload"));
+
+ /* Sanity checks */
+ if (!id_len || !key_len || !id || !key || !cipher_len || !cipher)
+ return NULL;
+
+ /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
+ 2 + cipher */
+ len = 2 + id_len + 2 + key_len + 2 + cipher_len;
+ buffer = silc_buffer_alloc(len);
+ if (!buffer)
+ return NULL;
+
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+
+ /* Encode the Channel Payload */
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_UI_XNSTRING(id, id_len),
+ SILC_STR_UI_SHORT(cipher_len),
+ SILC_STR_UI_XNSTRING(cipher, cipher_len),
+ SILC_STR_UI_SHORT(key_len),
+ SILC_STR_UI_XNSTRING(key, key_len),
+ SILC_STR_END);
+
+ return buffer;
+}
+
+/* Free's Channel Key Payload */
+
+void silc_channel_key_free_payload(SilcChannelKeyPayload payload)
+{
+ if (payload) {
+ if (payload->id)
+ silc_free(payload->id);
+ if (payload->cipher)
+ silc_free(payload->cipher);
+ if (payload->key) {
+ memset(payload->key, 0, payload->key_len);
+ silc_free(payload->key);
+ }
+ silc_free(payload);
+ }
+}
+
+/* Return ID */
+
+unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
+ unsigned int *id_len)
+{
+ if (id_len)
+ *id_len = payload->id_len;
+
+ return payload->id;
+}
+
+/* Return cipher name */
+
+unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
+ unsigned int *cipher_len)
+{
+ if (cipher_len)
+ *cipher_len = payload->cipher_len;
+
+ return payload->cipher;
+}
+
+/* Return key */
+
+unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
+ unsigned int *key_len)
+{
+ if (key_len)
+ *key_len = payload->key_len;
+
+ return payload->key;
+}
--- /dev/null
+/*
+
+ silcchannel.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCHANNEL_H
+#define SILCCHANNEL_H
+
+/* Forward declaration for Channel Payload parsed from packet. The
+ actual structure is defined in source file and is private data. */
+typedef struct SilcChannelPayloadStruct *SilcChannelPayload;
+
+/* Forward declaration for Channel Key Payload parsed from packet. The
+ actual structure is defined in source file and is private data. */
+typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
+
+/* Channel modes */
+#define SILC_CHANNEL_MODE_NONE 0x0000
+#define SILC_CHANNEL_MODE_PRIVATE 0x0001 /* private channel */
+#define SILC_CHANNEL_MODE_SECRET 0x0002 /* secret channel */
+#define SILC_CHANNEL_MODE_PRIVKEY 0x0004 /* channel has private key */
+#define SILC_CHANNEL_MODE_INVITE 0x0008 /* invite only channel */
+
+/* User modes on channel */
+#define SILC_CHANNEL_UMODE_NONE 0x0000
+#define SILC_CHANNEL_UMODE_CHANFO 0x0001 /* channel founder */
+#define SILC_CHANNEL_UMODE_CHANOP 0x0002 /* channel operator */
+
+/* Prototypes */
+SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer);
+SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
+ unsigned char *nick,
+ unsigned short data_len,
+ unsigned char *data,
+ unsigned short iv_len,
+ unsigned char *iv,
+ SilcRng rng);
+void silc_channel_free_payload(SilcChannelPayload payload);
+unsigned char *silc_channel_get_nickname(SilcChannelPayload payload,
+ unsigned int *nick_len);
+unsigned char *silc_channel_get_data(SilcChannelPayload payload,
+ unsigned int *data_len);
+unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
+ unsigned int *iv_len);
+SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer);
+SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
+ unsigned char *id,
+ unsigned short cipher_len,
+ unsigned char *cipher,
+ unsigned short key_len,
+ unsigned char *key);
+void silc_channel_key_free_payload(SilcChannelKeyPayload payload);
+unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
+ unsigned int *id_len);
+unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
+ unsigned int *cipher_len);
+unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
+ unsigned int *key_len);
+
+#endif
--- /dev/null
+/*
+
+ silccommand.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silccommand.h"
+
+/* Command Payload structure. Contents of this structure is parsed
+ from SILC packets. */
+struct SilcCommandPayloadStruct {
+ SilcCommand cmd;
+ unsigned int argc;
+ unsigned char **argv;
+ unsigned int *argv_lens;
+ unsigned int *argv_types;
+ unsigned int pos;
+};
+
+/* Length of the command payload */
+#define SILC_COMMAND_PAYLOAD_LEN 4
+
+/* Parses command payload returning new command payload structure */
+
+SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer)
+{
+ SilcCommandPayload new;
+ unsigned short payload_len = 0;
+ unsigned char args_num = 0;
+ unsigned char arg_num = 0;
+ unsigned int arg_type = 0;
+ unsigned int pull_len = 0;
+ int i = 0;
+
+ SILC_LOG_DEBUG(("Parsing command payload"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new command payload"));
+ return NULL;
+ }
+
+ /* Parse the Command Payload */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_CHAR(&new->cmd),
+ SILC_STR_UI_CHAR(&args_num),
+ SILC_STR_UI_SHORT(&payload_len),
+ SILC_STR_END);
+
+ if (payload_len != buffer->len) {
+ SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
+ return NULL;
+ }
+
+ if (new->cmd == 0)
+ return NULL;
+
+ if (args_num && payload_len) {
+
+ new->argv = silc_calloc(args_num, sizeof(unsigned char *));
+ new->argv_lens = silc_calloc(args_num, sizeof(unsigned int));
+ new->argv_types = silc_calloc(args_num, sizeof(unsigned int));
+
+ silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
+ pull_len += SILC_COMMAND_PAYLOAD_LEN;
+
+ /* Parse Command Argument Payloads */
+ arg_num = 1;
+ while(arg_num) {
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_CHAR(&arg_num),
+ SILC_STR_UI_CHAR(&arg_type),
+ SILC_STR_UI_SHORT(&payload_len),
+ SILC_STR_END);
+
+ /* Check that argument number is correct */
+ if (arg_num != i + 1)
+ goto err;
+
+ new->argv_lens[i] = payload_len;
+ new->argv_types[i] = arg_type;
+
+ /* Get argument data */
+ silc_buffer_pull(buffer, 4);
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i],
+ payload_len),
+ SILC_STR_END);
+ silc_buffer_pull(buffer, payload_len);
+ pull_len += 4 + payload_len;
+
+ i++;
+
+ if (i == args_num)
+ break;
+ }
+
+ /* Check the number of arguments */
+ if (arg_num != args_num)
+ goto err;
+ }
+
+ new->argc = i;
+ new->pos = 0;
+
+ silc_buffer_push(buffer, pull_len);
+
+ return new;
+
+ err:
+ if (i) {
+ int k;
+
+ for (k = 0; k < i; k++)
+ silc_free(new->argv[k]);
+ }
+
+ silc_free(new->argv);
+ silc_free(new->argv_lens);
+ silc_free(new->argv_types);
+
+ if (new)
+ silc_free(new);
+
+ return NULL;
+}
+
+/* Encodes Command Payload returning it to SilcBuffer. */
+
+SilcBuffer silc_command_encode_payload(SilcCommand cmd,
+ unsigned int argc,
+ unsigned char **argv,
+ unsigned int *argv_lens,
+ unsigned int *argv_types)
+{
+ SilcBuffer buffer;
+ unsigned int len;
+ int i;
+
+ SILC_LOG_DEBUG(("Encoding command payload"));
+
+ len = 1 + 1 + 2;
+ for (i = 0; i < argc; i++)
+ len += 1 + 1 + 2 + argv_lens[i];
+
+ buffer = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+
+ /* Create Command payload */
+ silc_buffer_format(buffer,
+ SILC_STR_UI_CHAR(cmd),
+ SILC_STR_UI_CHAR(argc),
+ SILC_STR_UI_SHORT(len),
+ SILC_STR_END);
+
+ /* Put arguments */
+ if (argc) {
+ silc_buffer_pull(buffer, 4);
+
+ for (i = 0; i < argc; i++) {
+ silc_buffer_format(buffer,
+ SILC_STR_UI_CHAR(i + 1),
+ SILC_STR_UI_CHAR(argv_types[i]),
+ SILC_STR_UI_SHORT(argv_lens[i]),
+ SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
+ SILC_STR_END);
+ silc_buffer_pull(buffer, 4 + argv_lens[i]);
+ }
+
+ silc_buffer_push(buffer, len);
+ }
+
+ return buffer;
+}
+
+/* Encodes Command payload with variable argument list. The arguments
+ must be: unsigned char *, unsigned int, ... One unsigned char *
+ and unsigned int forms one argument, hence `argc' in case when
+ sending one unsigned char * and unsigned int equals one (1) and
+ when sending two of those it equals two (2), and so on. This has
+ to be preserved or bad things will happen. */
+
+SilcBuffer silc_command_encode_payload_va(SilcCommand cmd,
+ unsigned int argc, ...)
+{
+ va_list ap;
+ unsigned char **argv;
+ unsigned int *argv_lens = NULL, *argv_types = NULL;
+ unsigned char *x;
+ unsigned int x_len;
+ SilcBuffer buffer;
+ int i;
+
+ va_start(ap, argc);
+
+ argv = silc_calloc(argc, sizeof(unsigned char *));
+ argv_lens = silc_calloc(argc, sizeof(unsigned int));
+ argv_types = silc_calloc(argc, sizeof(unsigned int));
+
+ for (i = 0; i < argc; i++) {
+ x = va_arg(ap, unsigned char *);
+ x_len = va_arg(ap, unsigned int);
+
+ argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+ memcpy(argv[i], x, x_len);
+ argv_lens[i] = x_len;
+ argv_types[i] = i + 1;
+ }
+
+ buffer = silc_command_encode_payload(cmd, argc, argv,
+ argv_lens, argv_types);
+
+ for (i = 0; i < argc; i++)
+ silc_free(argv[i]);
+ silc_free(argv);
+ silc_free(argv_lens);
+ silc_free(argv_types);
+
+ return buffer;
+}
+
+/* Free's Command Payload */
+
+void silc_command_free_payload(SilcCommandPayload payload)
+{
+ int i;
+
+ if (payload) {
+ for (i = 0; i < payload->argc; i++)
+ silc_free(payload->argv[i]);
+
+ silc_free(payload->argv);
+ silc_free(payload);
+ }
+}
+
+/* Returns the command type in payload */
+
+SilcCommand silc_command_get(SilcCommandPayload payload)
+{
+ return payload->cmd;
+}
+
+/* Returns number of arguments in payload */
+
+unsigned int silc_command_get_arg_num(SilcCommandPayload payload)
+{
+ return payload->argc;
+}
+
+/* Returns first argument from payload. */
+
+unsigned char *silc_command_get_first_arg(SilcCommandPayload payload,
+ unsigned int *ret_len)
+{
+ payload->pos = 0;
+
+ if (ret_len)
+ *ret_len = payload->argv_lens[payload->pos];
+
+ return payload->argv[payload->pos++];
+}
+
+/* Returns next argument from payload or NULL if no more arguments. */
+
+unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
+ unsigned int *ret_len)
+{
+ if (payload->pos >= payload->argc)
+ return NULL;
+
+ if (ret_len)
+ *ret_len = payload->argv_lens[payload->pos];
+
+ return payload->argv[payload->pos++];
+}
+
+/* Returns argument which type is `type'. */
+
+unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
+ unsigned int type,
+ unsigned int *ret_len)
+{
+ int i;
+
+ for (i = 0; i < payload->argc; i++)
+ if (payload->argv_types[i] == type)
+ break;
+
+ if (i >= payload->argc)
+ return NULL;
+
+ if (ret_len)
+ *ret_len = payload->argv_lens[i];
+
+ return payload->argv[i];
+}
+
+/* Encodes command status payload. Status payload is sent as one reply
+ argument. The returned payload still has to be saved into the
+ Command Argument payload. */
+
+SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status,
+ unsigned char *data,
+ unsigned int len)
+{
+ SilcBuffer sp;
+
+ sp = silc_buffer_alloc(len + 2);
+ silc_buffer_pull_tail(sp, SILC_BUFFER_END(sp));
+ silc_buffer_format(sp,
+ SILC_STR_UI_SHORT(status),
+ SILC_STR_UI_XNSTRING(data, len),
+ SILC_STR_END);
+
+ return sp;
+}
--- /dev/null
+/*
+
+ silccommand.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCOMMAND_H
+#define SILCCOMMAND_H
+
+/* Command function callback. The actual command function pointer. */
+typedef void (*SilcCommandCb)(void *context);
+
+/* Typedefinition for SILC commands. */
+typedef unsigned char SilcCommand;
+
+/* Forward declaration for Command Payload parsed from packet. The
+ actual structure is defined in source file and is private data. */
+typedef struct SilcCommandPayloadStruct *SilcCommandPayload;
+
+/* Command flags. These set how the commands behave on different
+ situations. These can be OR'ed together to set multiple flags. */
+typedef enum {
+ SILC_CF_NONE = 0,
+
+ /* Command may only be used once per (about) 2 seconds */
+ SILC_CF_LAG = (1L << 1),
+
+ /* Command is available for registered connections (connections
+ whose ID has been created. */
+ SILC_CF_REG = (1L << 2),
+
+ /* Command is available only for server operators */
+ SILC_CF_OPER = (1L << 3),
+
+ /* Command is available only for SILC (router) operators. If this
+ is set SILC_CF_OPER is not necessary to be set. */
+ SILC_CF_SILC_OPER = (1L << 4),
+
+} SilcCommandFlag;
+
+/* All SILC commands. These are commands that have client and server
+ counterparts. These are pretty much the same as in IRC. */
+#define SILC_COMMAND_NONE 0
+#define SILC_COMMAND_WHOIS 2
+#define SILC_COMMAND_WHOWAS 3
+#define SILC_COMMAND_IDENTIFY 4
+#define SILC_COMMAND_NICK 5
+#define SILC_COMMAND_LIST 6
+#define SILC_COMMAND_TOPIC 7
+#define SILC_COMMAND_INVITE 8
+#define SILC_COMMAND_QUIT 9
+#define SILC_COMMAND_KILL 10
+#define SILC_COMMAND_INFO 11
+#define SILC_COMMAND_CONNECT 12
+#define SILC_COMMAND_PING 13
+#define SILC_COMMAND_OPER 14
+#define SILC_COMMAND_JOIN 15
+#define SILC_COMMAND_MOTD 16
+#define SILC_COMMAND_UMODE 17
+#define SILC_COMMAND_CMODE 18
+#define SILC_COMMAND_KICK 19
+#define SILC_COMMAND_RESTART 20
+#define SILC_COMMAND_CLOSE 21
+#define SILC_COMMAND_DIE 22
+#define SILC_COMMAND_SILCOPER 23
+#define SILC_COMMAND_LEAVE 24
+#define SILC_COMMAND_NAMES 25
+
+/* Local commands. Local commands are unofficial commands and
+ are implementation specific commands. These are used only by the
+ SILC client to extend user commands. */
+#define SILC_COMMAND_HELP 100
+#define SILC_COMMAND_CLEAR 101
+#define SILC_COMMAND_VERSION 102
+#define SILC_COMMAND_SERVER 103
+#define SILC_COMMAND_MSG 104
+#define SILC_COMMAND_AWAY 105
+
+/* Reserved */
+#define SILC_COMMAND_RESERVED 255
+
+/* Command Status type */
+typedef unsigned short SilcCommandStatus;
+
+/* Command Status messages */
+#define SILC_STATUS_OK 0
+#define SILC_STATUS_LIST_START 1
+#define SILC_STATUS_LIST_END 2
+#define SILC_STATUS_ERR_NO_SUCH_NICK 10
+#define SILC_STATUS_ERR_NO_SUCH_CHANNEL 11
+#define SILC_STATUS_ERR_NO_SUCH_SERVER 12
+#define SILC_STATUS_ERR_TOO_MANY_TARGETS 13
+#define SILC_STATUS_ERR_NO_RECIPIENT 14
+#define SILC_STATUS_ERR_UNKNOWN_COMMAND 15
+#define SILC_STATUS_ERR_WILDCARDS 16
+#define SILC_STATUS_ERR_NO_CLIENT_ID 17
+#define SILC_STATUS_ERR_NO_CHANNEL_ID 18
+#define SILC_STATUS_ERR_BAD_CLIENT_ID 19
+#define SILC_STATUS_ERR_BAD_CHANNEL_ID 20
+#define SILC_STATUS_ERR_NO_SUCH_CLIENT_ID 21
+#define SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID 22
+#define SILC_STATUS_ERR_NICKNAME_IN_USE 23
+#define SILC_STATUS_ERR_NOT_ON_CHANNEL 24
+#define SILC_STATUS_ERR_USER_ON_CHANNEL 25
+#define SILC_STATUS_ERR_NOT_REGISTERED 26
+#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS 27
+#define SILC_STATUS_ERR_TOO_MANY_PARAMS 28
+#define SILC_STATUS_ERR_PERM_DENIED 29
+#define SILC_STATUS_ERR_BANNED_FROM_SERVER 30
+#define SILC_STATUS_ERR_BAD_PASSWORD 31
+#define SILC_STATUS_ERR_CHANNEL_IS_FULL 32
+#define SILC_STATUS_ERR_NOT_INVITED 33
+#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 34
+#define SILC_STATUS_ERR_UNKNOWN_MODE 35
+#define SILC_STATUS_ERR_NOT_YOU 36
+#define SILC_STATUS_ERR_NO_CHANNEL_PRIV 37
+#define SILC_STATUS_ERR_NO_SERVER_PRIV 38
+#define SILC_STATUS_ERR_NO_ROUTER_PRIV 39
+#define SILC_STATUS_ERR_BAD_NICKNAME 40
+#define SILC_STATUS_ERR_BAD_CHANNEL 41
+#define SILC_STATUS_ERR_AUTH_FAILED 42
+
+/* Prototypes */
+SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer);
+SilcBuffer silc_command_encode_payload(SilcCommand cmd,
+ unsigned int argc,
+ unsigned char **argv,
+ unsigned int *argv_lens,
+ unsigned int *argv_types);
+SilcBuffer silc_command_encode_payload_va(SilcCommand cmd,
+ unsigned int argc, ...);
+void silc_command_free_payload(SilcCommandPayload payload);
+SilcCommand silc_command_get(SilcCommandPayload payload);
+unsigned int silc_command_get_arg_num(SilcCommandPayload payload);
+unsigned char *silc_command_get_first_arg(SilcCommandPayload payload,
+ unsigned int *ret_len);
+unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
+ unsigned int *ret_len);
+unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
+ unsigned int type,
+ unsigned int *ret_len);
+SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status,
+ unsigned char *data,
+ unsigned int len);
+
+#endif
--- /dev/null
+/*
+
+ silcconfig.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Opens and reads a configuration file to a buffer. The read data is
+ returned to the ret_buffer argument. */
+
+void silc_config_open(char *filename, SilcBuffer *ret_buffer)
+{
+ char *buffer;
+ int filelen;
+
+ buffer = silc_file_read(filename, &filelen);
+ if (buffer == NULL)
+ return;
+
+ /* Buffer don't have EOF, but we'll need it. */
+ buffer[filelen] = EOF;
+
+ *ret_buffer = silc_buffer_alloc(filelen + 1);
+ silc_buffer_pull_tail(*ret_buffer, filelen + 1);
+ silc_buffer_put(*ret_buffer, buffer, filelen + 1);
+
+ SILC_LOG_DEBUG(("Config file `%s' opened", filename));
+}
+
+/* Returns next token from a buffer to the dest argument. Returns the
+ length of the token. This is used to take tokens from a configuration
+ line. */
+
+int silc_config_get_token(SilcBuffer buffer, char **dest)
+{
+ int len;
+
+ if (strchr(buffer->data, ':')) {
+ len = strcspn(buffer->data, ":");
+ if (len) {
+ *dest = silc_calloc(len + 1, sizeof(char));
+ memset(*dest, 0, len + 1);
+ memcpy(*dest, buffer->data, len);
+ }
+ silc_buffer_pull(buffer, len + 1);
+ return len;
+ }
+
+ return -1;
+}
+
+/* Returns number of tokens in a buffer. */
+
+int silc_config_check_num_token(SilcBuffer buffer)
+{
+ int len, len2, num;
+
+ if (strchr(buffer->data, ':')) {
+ len = 0;
+ num = 0;
+ while (strchr(buffer->data + len, ':')) {
+ num++;
+ len2 = strcspn(buffer->data + len, ":") + 1;
+ len += len2;
+ }
+
+ return num;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+
+ silcconfig.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCONFIG_H
+#define SILCCONFIG_H
+
+/* Prototypes */
+void silc_config_open(char *filename, SilcBuffer *ret_buffer);
+int silc_config_get_token(SilcBuffer buffer, char **dest);
+int silc_config_check_num_token(SilcBuffer);
+
+#endif
--- /dev/null
+/*
+
+ silclog.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* SILC Log name strings. These strings are printed to the log file. */
+const SilcLogTypeName silc_log_types[] =
+{
+ { "Info", SILC_LOG_INFO },
+ { "Warning", SILC_LOG_WARNING },
+ { "Error", SILC_LOG_ERROR },
+ { "Fatal", SILC_LOG_FATAL },
+
+ { NULL, -1 },
+};
+
+char *log_info_file;
+char *log_warning_file;
+char *log_error_file;
+char *log_fatal_file;
+unsigned int log_info_size;
+unsigned int log_warning_size;
+unsigned int log_error_size;
+unsigned int log_fatal_size;
+
+/* Formats arguments to a string and returns it after allocating memory
+ for it. It must be remembered to free it later. */
+
+char *silc_log_format(char *fmt, ...)
+{
+ va_list args;
+ static char buf[1024];
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+
+ return strdup(buf);
+}
+
+/* Outputs the log message to what ever log file selected. */
+
+void silc_log_output(const char *filename, unsigned int maxsize,
+ SilcLogType type, char *string)
+{
+ FILE *fp;
+ const SilcLogTypeName *np;
+
+ /* Purge the log file if the max size is defined. */
+ if (maxsize) {
+ fp = fopen(filename, "r");
+ if (fp) {
+ int filelen;
+
+ filelen = fseek(fp, (off_t)0L, SEEK_END);
+ fseek(fp, (off_t)0L, SEEK_SET);
+
+ /* Purge? */
+ if (maxsize >= filelen)
+ unlink(filename);
+ }
+ }
+
+ /* Open the log file */
+ if ((fp = fopen(filename, "a+")) == NULL) {
+ fprintf(stderr, "warning: could not open log file "
+ "%s: %s\n", filename, strerror(errno));
+ fprintf(stderr, "warning: log messages will be displayed on the screen\n");
+ fp = stderr;
+ }
+
+ /* Get the log type name */
+ for(np = silc_log_types; np->name; np++) {
+ if (np->type == type)
+ break;
+ }
+
+ fprintf(fp, "[%s] [%s] %s\n", silc_get_time(), np->name, string);
+ fflush(fp);
+ fclose(fp);
+ silc_free(string);
+}
+
+/* Outputs the debug message to stderr. */
+
+void silc_log_output_debug(char *file, char *function,
+ int line, char *string)
+{
+ /* fprintf(stderr, "%s:%s:%d: %s\n", file, function, line, string); */
+ fprintf(stderr, "%s:%d: %s\n", function, line, string);
+ fflush(stderr);
+ silc_free(string);
+}
+
+/* Hexdumps a message */
+
+void silc_log_output_hexdump(char *file, char *function,
+ int line, void *data_in,
+ unsigned int len, char *string)
+{
+ int i, k;
+ int off, pos, count;
+ unsigned char *data = (unsigned char *)data_in;
+
+ /* fprintf(stderr, "%s:%s:%d: %s\n", file, function, line, string); */
+ fprintf(stderr, "%s:%d: %s\n", function, line, string);
+ silc_free(string);
+
+ k = 0;
+ off = len % 16;
+ pos = 0;
+ count = 16;
+ while (1) {
+
+ if (off) {
+ if ((len - pos) < 16 && (len - pos <= len - off))
+ count = off;
+ } else {
+ if (pos == len)
+ count = 0;
+ }
+ if (off == len)
+ count = len;
+
+ if (count)
+ fprintf(stderr, "%08X ", k++ * 16);
+
+ for (i = 0; i < count; i++) {
+ fprintf(stderr, "%02X ", data[pos + i]);
+
+ if ((i + 1) % 4 == 0)
+ fprintf(stderr, " ");
+ }
+
+ if (count && count < 16) {
+ int j;
+
+ for (j = 0; j < 16 - count; j++) {
+ fprintf(stderr, " ");
+
+ if ((j + count + 1) % 4 == 0)
+ fprintf(stderr, " ");
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ char ch;
+
+ if (data[pos] < 32 || data[pos] >= 127)
+ ch = '.';
+ else
+ ch = data[pos];
+
+ fprintf(stderr, "%c", ch);
+ pos++;
+ }
+
+ if (count)
+ fprintf(stderr, "\n");
+
+ if (count < 16)
+ break;
+ }
+}
+
+/* Sets log files */
+
+void silc_log_set_files(char *info, unsigned int info_size,
+ char *warning, unsigned int warning_size,
+ char *error, unsigned int error_size,
+ char *fatal, unsigned int fatal_size)
+{
+ log_info_file = info;
+ log_warning_file = warning;
+ log_error_file = error;
+ log_fatal_file = fatal;
+
+ log_info_size = info_size;
+ log_warning_size = warning_size;
+ log_error_size = error_size;
+ log_fatal_size = fatal_size;
+}
--- /dev/null
+/*
+
+ silclog.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCLOG_H
+#define SILCLOG_H
+
+/* SILC Log types */
+typedef enum {
+ SILC_LOG_INFO,
+ SILC_LOG_WARNING,
+ SILC_LOG_ERROR,
+ SILC_LOG_FATAL
+} SilcLogType;
+
+/* Log type name structure. */
+typedef struct {
+ char *name;
+ SilcLogType type;
+} SilcLogTypeName;
+
+/* Default log filenames */
+#define SILC_LOG_FILE_INFO "silcd.log"
+#define SILC_LOG_FILE_WARNING "silcd_error.log"
+#define SILC_LOG_FILE_ERROR SILC_LOG_FILE_WARNING
+#define SILC_LOG_FILE_FATAL SILC_LOG_FILE_WARNING
+
+/* Log files. Set by silc_log_set_logfiles. */
+extern char *log_info_file;
+extern char *log_warning_file;
+extern char *log_error_file;
+extern char *log_fatal_file;
+extern unsigned int log_info_size;
+extern unsigned int log_warning_size;
+extern unsigned int log_error_size;
+extern unsigned int log_fatal_size;
+
+/* Log macros. */
+#define SILC_LOG_INFO(fmt) silc_log_output(log_info_file, \
+ log_info_size, \
+ SILC_LOG_INFO, \
+ silc_log_format fmt))
+#define SILC_LOG_WARNING(fmt) (silc_log_output(log_warning_file, \
+ log_warning_size, \
+ SILC_LOG_WARNING, \
+ silc_log_format fmt))
+#define SILC_LOG_ERROR(fmt) (silc_log_output(log_error_file, \
+ log_error_size, \
+ SILC_LOG_ERROR, \
+ silc_log_format fmt))
+#define SILC_LOG_FATAL(fmt) (silc_log_output(log_fatal_file, \
+ log_fatal_size, \
+ SILC_LOG_FATAL, \
+ silc_log_format fmt))
+
+/* Debug macro is a bit different from other logging macros and it
+ is compiled in only if debugging is enabled. */
+#ifdef SILC_DEBUG
+#define SILC_LOG_DEBUG(fmt) (silc_log_output_debug(__FILE__, \
+ __FUNCTION__, \
+ __LINE__, \
+ silc_log_format fmt))
+#define SILC_LOG_HEXDUMP(fmt, data, len) \
+ (silc_log_output_hexdump(__FILE__, \
+ __FUNCTION__, \
+ __LINE__, \
+ (data), (len), \
+ silc_log_format fmt))
+#else
+#define SILC_LOG_DEBUG(fmt)
+#define SILC_LOG_HEXDUMP(fmt, data, len)
+#endif
+
+/* Prototypes */
+char *silc_log_format(char *fmt, ...);
+void silc_log_output_debug(char *file, char *function,
+ int line, char *string);
+void silc_log_output(const char *filename, unsigned int maxsize,
+ SilcLogType type, char *string);
+void silc_log_output_hexdump(char *file, char *function,
+ int line, void *data_in,
+ unsigned int len, char *string);
+void silc_log_set_files(char *info, unsigned int info_size,
+ char *warning, unsigned int warning_size,
+ char *error, unsigned int error_size,
+ char *fatal, unsigned int fatal_size);
+
+#endif
--- /dev/null
+/*
+
+ silcmemory.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1999 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+void *silc_malloc(size_t size)
+{
+#ifdef HAVE_MLOCK
+ void *addr = malloc(size);
+ mlock(addr, size);
+ return addr;
+#else
+ return malloc(size);
+#endif
+}
+
+void *silc_calloc(size_t items, size_t size)
+{
+#ifdef HAVE_MLOCK
+ void *addr = calloc(items, size);
+ mlock(addr, size);
+ return addr;
+#else
+ return calloc(items, size);
+#endif
+}
+
+void *silc_realloc(void *ptr, size_t size)
+{
+#ifdef HAVE_MLOCK
+ void *addr = realloc(ptr, size);
+ mlock(addr, size);
+ return addr;
+#else
+ return realloc(ptr, size);
+#endif
+}
+
+void silc_free(void *ptr)
+{
+ free(ptr);
+}
+
+
+
+
+
+
+
--- /dev/null
+/*
+
+ silcmemory.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1999 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCMEMORY_H
+#define SILCMEMORY_H
+
+/* Prototypes */
+void *silc_malloc(size_t size);
+void *silc_calloc(size_t items, size_t size);
+void *silc_realloc(void *ptr, size_t size);
+void silc_free(void *ptr);
+
+#endif
+
+
+
+
+
+
--- /dev/null
+/*
+
+ silcnet.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcnet.h"
+
+/* This function creates server or daemon or listener or what ever. This
+ does not fork a new process, it must be done by the caller if caller
+ wants to create a child process. This is used by the SILC server.
+ If argument `ip_addr' is NULL `any' address will be used. Returns
+ the created socket or -1 on error. */
+
+int silc_net_create_server(int port, char *ip_addr)
+{
+ int sock, rval;
+ struct sockaddr_in server;
+
+ SILC_LOG_DEBUG(("Creating a new server listener"));
+
+ /* Create the socket */
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+ return -1;
+ }
+
+ /* Set the socket options */
+ rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+ return -1;
+ }
+
+ /* Set the socket information for bind() */
+ memset(&server, 0, sizeof(server));
+ server.sin_family = PF_INET;
+ server.sin_port = htons(port);
+
+ /* Convert IP address to network byte order */
+ if (ip_addr)
+ inet_aton(ip_addr, &server.sin_addr);
+ else
+ server.sin_addr.s_addr = INADDR_ANY;
+
+ /* Bind the server socket */
+ rval = bind(sock, (struct sockaddr *)&server, sizeof(server));
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno)));
+ return -1;
+ }
+
+ /* Specify that we are listenning */
+ rval = listen(sock, 5);
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno)));
+ return -1;
+ }
+
+ /* Set the server socket to non-blocking mode */
+ silc_net_set_socket_nonblock(sock);
+
+ SILC_LOG_DEBUG(("Server listener created, fd=%d", sock));
+
+ return sock;
+}
+
+void silc_net_close_server(int sock)
+{
+ shutdown(sock, 2);
+ close(sock);
+
+ SILC_LOG_DEBUG(("Server socket closed"));
+}
+
+/* Creates a connection (TCP/IP) to a remote host. Returns the connection
+ socket or -1 on error. This blocks the process while trying to create
+ the connection. */
+
+int silc_net_create_connection(int port, char *host)
+{
+ int sock, rval;
+ struct hostent *dest;
+ struct sockaddr_in desthost;
+
+ SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port));
+
+ /* Do host lookup */
+ dest = gethostbyname(host);
+ if (!dest) {
+ SILC_LOG_ERROR(("Network (%s) unreachable", host));
+ return -1;
+ }
+
+ /* Set socket information */
+ memset(&desthost, 0, sizeof(desthost));
+ desthost.sin_port = htons(port);
+ memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
+
+ /* Create the connection socket */
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+ return -1;
+ }
+
+ /* Connect to the host */
+ rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
+ shutdown(sock, 2);
+ close(sock);
+ return -1;
+ }
+
+ /* Set appropriate option */
+ silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+
+ SILC_LOG_DEBUG(("Connection created"));
+
+ return sock;
+}
+
+/* Creates a connection (TCP/IP) to a remote host. Returns the connection
+ socket or -1 on error. This creates non-blocking socket hence the
+ connection returns directly. To get the result of the connect() one
+ must select() the socket and read the result after it's ready. */
+
+int silc_net_create_connection_async(int port, char *host)
+{
+ int sock, rval;
+ struct hostent *dest;
+ struct sockaddr_in desthost;
+
+ SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d",
+ host, port));
+
+ /* Do host lookup */
+ dest = gethostbyname(host);
+ if (!dest) {
+ SILC_LOG_ERROR(("Network (%s) unreachable", host));
+ return -1;
+ }
+
+ /* Set socket information */
+ memset(&desthost, 0, sizeof(desthost));
+ desthost.sin_port = htons(port);
+ memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
+
+ /* Create the connection socket */
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+ return -1;
+ }
+
+ /* Set the socket to non-blocking mode */
+ silc_net_set_socket_nonblock(sock);
+
+ /* Connect to the host */
+ rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
+ if (rval < 0) {
+ if (errno != EINPROGRESS) {
+ SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
+ shutdown(sock, 2);
+ close(sock);
+ return -1;
+ }
+ }
+
+ /* Set appropriate option */
+ silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+
+ SILC_LOG_DEBUG(("Connection operation in progress"));
+
+ return sock;
+}
+
+/* Closes the connection */
+
+void silc_net_close_connection(int sock)
+{
+ close(sock);
+}
+
+/* Accepts a connection from a particular socket */
+
+int silc_net_accept_connection(int sock)
+{
+ return accept(sock, 0, 0);
+}
+
+/* Set's the socket to non-blocking mode. */
+
+int silc_net_set_socket_nonblock(int sock)
+{
+ return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
+}
+
+/* Sets a option for a socket. */
+
+int silc_net_set_socket_opt(int sock, int level, int option, int on)
+{
+ return setsockopt(sock, level, option, (void *)&on, sizeof(on));
+}
+
+/* Checks whether IP address sent as argument is valid IP address. */
+
+int silc_net_is_ip(const char *addr)
+{
+ struct in_addr tmp;
+ return inet_aton(addr, &tmp);
+}
+
+/* Performs lookups for remote name and IP address. */
+
+void silc_net_check_host_by_sock(int sock, char **hostname, char **ip)
+{
+ struct sockaddr_in remote;
+ struct hostent *dest;
+ char *host_ip = NULL;
+ char host_name[1024];
+ int rval, len;
+ int i;
+
+ *hostname = NULL;
+ *ip = NULL;
+
+ SILC_LOG_DEBUG(("Resolving remote hostname and IP address"));
+
+ memset(&remote, 0, sizeof(remote));
+ len = sizeof(remote);
+ rval = getpeername(sock, (struct sockaddr *)&remote, &len);
+ if (rval < 0)
+ return;
+
+ /* Get host by address */
+ dest = gethostbyaddr((char *)&remote.sin_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (!dest)
+ return;
+
+ /* Get same hsot by name to see that the remote host really is
+ the who it says it is */
+ memset(host_name, 0, sizeof(host_name));
+ memcpy(host_name, dest->h_name, strlen(dest->h_name));
+ dest = gethostbyname(host_name);
+ if (!dest)
+ return;
+
+ /* Find the address from list */
+ for (i = 0; dest->h_addr_list[i]; i++)
+ if (!memcmp(dest->h_addr_list[i], &remote.sin_addr,
+ sizeof(struct in_addr)))
+ break;
+ if (!dest->h_addr_list[i])
+ return;
+
+ host_ip = inet_ntoa(remote.sin_addr);
+ if (!host_ip)
+ return;
+
+ *hostname = silc_calloc(strlen(host_name) + 1, sizeof(char));
+ memcpy(*hostname, host_name, strlen(host_name));
+ SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));
+ *ip = silc_calloc(strlen(host_ip) + 1, sizeof(char));
+ memcpy(*ip, host_ip, strlen(host_ip));
+ SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
+}
--- /dev/null
+/*
+
+ silcnet.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCNET_H
+#define SILCNET_H
+
+/* Prototypes */
+int silc_net_create_server(int port, char *ip_addr);
+void silc_net_close_server(int sock);
+int silc_net_create_connection(int port, char *host);
+int silc_net_create_connection_async(int port, char *host);
+void silc_net_close_connection(int sock);
+int silc_net_accept_connection(int sock);
+int silc_net_set_socket_nonblock(int sock);
+int silc_net_set_socket_opt(int sock, int level, int option, int on);
+int silc_net_is_ip(const char *addr);
+void silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
+
+#endif
--- /dev/null
+/*
+
+ silcpacket.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Created: Fri Jul 25 18:52:14 1997
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Writes data from encrypted buffer to the socket connection. If the
+ data cannot be written at once, it will be written later with a timeout.
+ The data is written from the data section of the buffer, not from head
+ or tail section. This automatically pulls the data section towards end
+ after writing the data. */
+
+int silc_packet_write(int sock, SilcBuffer src)
+{
+ int ret = 0;
+
+ SILC_LOG_DEBUG(("Writing data to socket %d", sock));
+
+ if (src->len > 0) {
+ ret = write(sock, src->data, src->len);
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
+ return -2;
+ }
+ SILC_LOG_ERROR(("Cannot write to socket: %s", strerror(errno)));
+ return -1;
+ }
+
+ silc_buffer_pull(src, ret);
+ }
+
+ SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
+
+ return ret;
+}
+
+/* Reads data from the socket connection into the incoming data buffer.
+ However, this does not parse the packet, it only reads some amount from
+ the network. If there are more data available that can be read at a time
+ the rest of the data will be read later with a timeout and only after
+ that the packet is ready to be parsed.
+
+ The destination buffer sent as argument must be initialized before
+ calling this function, and, the data section and the start of the tail
+ section must be same. Ie. we add the read data to the tail section of
+ the buffer hence the data section is the start of the buffer.
+
+ This returns amount of bytes read or -1 on error or -2 on case where
+ all of the data could not be read at once. */
+
+int silc_packet_read(int sock, SilcBuffer dest)
+{
+ int len = 0;
+ unsigned char buf[SILC_PACKET_READ_SIZE];
+
+ SILC_LOG_DEBUG(("Reading data from socket %d", sock));
+
+ /* Read the data from the socket. */
+ len = read(sock, buf, sizeof(buf));
+ if (len < 0) {
+ if (errno == EAGAIN) {
+ SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
+ return -2;
+ }
+ SILC_LOG_ERROR(("Cannot read from socket: %d", strerror(errno)));
+ return -1;
+ }
+
+ if (!len)
+ return 0;
+
+ /* Insert the data to the buffer. If the data doesn't fit to the
+ buffer space is allocated for the buffer.
+ XXX: I don't like this. -Pekka */
+ if (dest) {
+
+ /* If the data doesn't fit we just have to allocate a whole new
+ data area */
+ if (dest->truelen <= len) {
+
+ /* Free the old buffer */
+ memset(dest->head, 'F', dest->truelen);
+ silc_free(dest->head);
+
+ /* Allocate new data area */
+ len += SILC_PACKET_DEFAULT_SIZE;
+ dest->data = silc_calloc(len, sizeof(char));
+ dest->truelen = len;
+ dest->len = 0;
+ dest->head = dest->data;
+ dest->data = dest->data;
+ dest->tail = dest->data;
+ dest->end = dest->data + dest->truelen;
+ len -= SILC_PACKET_DEFAULT_SIZE;
+ }
+
+ silc_buffer_put_tail(dest, buf, len);
+ silc_buffer_pull_tail(dest, len);
+ }
+
+ SILC_LOG_DEBUG(("Read %d bytes", len));
+
+ return len;
+}
+
+/* Encrypts a packet. */
+
+void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
+ unsigned int len)
+{
+ SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)",
+ cipher->cipher->name, len, len - 2));
+
+ /* Encrypt the data area of the packet. 3 bytes of the packet
+ are not encrypted. */
+ cipher->cipher->encrypt(cipher->context, buffer->data + 2,
+ buffer->data + 2, len - 2, cipher->iv);
+
+}
+
+/* Decrypts a packet. */
+
+void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer,
+ unsigned int len)
+{
+ SILC_LOG_DEBUG(("Decrypting packet, cipher %s, len %d (%d)",
+ cipher->cipher->name, len, len - 2));
+
+ /* Decrypt the data area of the packet. 2 bytes of the packet
+ are not decrypted (they are not encrypted). */
+ cipher->cipher->decrypt(cipher->context, buffer->data + 2,
+ buffer->data + 2, len - 2, cipher->iv);
+
+}
+
+/* Parses the packet. This is called when a whole packet is ready to be
+ parsed. The buffer sent must be already decrypted before calling this
+ function. The len argument must be the true length of the packet. This
+ function returns the type of the packet. The data section of the
+ buffer is parsed, not head or tail sections. */
+
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
+{
+ SilcBuffer buffer = ctx->buffer;
+ int len;
+
+ SILC_LOG_DEBUG(("Parsing incoming packet"));
+
+ /* Check the length of the buffer */
+ if (buffer->len < SILC_PACKET_MIN_LEN) {
+ SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
+ return SILC_PACKET_NONE;
+ }
+
+ /* Parse the buffer. This parses the SILC header of the packet. */
+ len = silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&ctx->truelen),
+ SILC_STR_UI_CHAR(&ctx->flags),
+ SILC_STR_UI_CHAR(&ctx->type),
+ SILC_STR_UI_SHORT(&ctx->src_id_len),
+ SILC_STR_UI_SHORT(&ctx->dst_id_len),
+ SILC_STR_UI_CHAR(&ctx->src_id_type),
+ SILC_STR_END);
+
+ if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
+ ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+ SILC_LOG_ERROR(("Bad ID lengths in packet"));
+ return SILC_PACKET_NONE;
+ }
+
+ /* Calculate length of padding in packet */
+ ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+
+ silc_buffer_pull(buffer, len);
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+ ctx->src_id_len),
+ SILC_STR_UI_CHAR(&ctx->dst_id_type),
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+ ctx->dst_id_len),
+ SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+ SILC_STR_END);
+ silc_buffer_push(buffer, len);
+
+ SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
+ ctx->buffer->data, ctx->buffer->len);
+
+ /* Pull SILC header and padding from packet */
+ silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
+ ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+
+ SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
+
+ return ctx->type;
+}
+
+/* Perform special SILC Packet header parsing. This is required to some
+ packet types that have the data payload encrypted with different key
+ than the header area plus padding of the packet. Hence, this parses
+ the header in a way that it does not take the data area into account
+ and parses the header and padding area only. */
+
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
+{
+ SilcBuffer buffer = ctx->buffer;
+ int len, tmplen;
+
+ SILC_LOG_DEBUG(("Parsing incoming packet"));
+
+ /* Check the length of the buffer */
+ if (buffer->len < SILC_PACKET_MIN_LEN) {
+ SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
+ return SILC_PACKET_NONE;
+ }
+
+ /* Parse the buffer. This parses the SILC header of the packet. */
+ len = silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&ctx->truelen),
+ SILC_STR_UI_CHAR(&ctx->flags),
+ SILC_STR_UI_CHAR(&ctx->type),
+ SILC_STR_UI_SHORT(&ctx->src_id_len),
+ SILC_STR_UI_SHORT(&ctx->dst_id_len),
+ SILC_STR_UI_CHAR(&ctx->src_id_type),
+ SILC_STR_END);
+
+ if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
+ ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+ SILC_LOG_ERROR(("Bad ID lengths in packet"));
+ return SILC_PACKET_NONE;
+ }
+
+ /* Calculate length of padding in packet. As this is special packet
+ the data area is not used in the padding calculation as it won't
+ be decrypted by the caller. */
+ tmplen = SILC_PACKET_HEADER_LEN + ctx->src_id_len + ctx->dst_id_len;
+ ctx->padlen = SILC_PACKET_PADLEN(tmplen);
+
+ silc_buffer_pull(buffer, len);
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+ ctx->src_id_len),
+ SILC_STR_UI_CHAR(&ctx->dst_id_type),
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+ ctx->dst_id_len),
+ SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+ SILC_STR_END);
+ silc_buffer_push(buffer, len);
+
+ SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
+ ctx->buffer->data, ctx->buffer->len);
+
+ /* Pull SILC header and padding from packet */
+ silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
+ ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+
+ SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
+
+ return ctx->type;
+}
+
+/* Assembles a new packet to be ready for send out. The buffer sent as
+ argument must include the data to be sent and it must not be encrypted.
+ The packet also must have enough free space so that the SILC header
+ and padding maybe added to the packet. The packet is encrypted after
+ this function has returned.
+
+ The buffer sent as argument should be something like following:
+
+ --------------------------------------------
+ | head | data | tail |
+ --------------------------------------------
+ ^ ^
+ 58 bytes x bytes
+
+ So that the SILC header and 1 - 16 bytes of padding can fit to
+ the buffer. After assembly the buffer might look like this:
+
+ --------------------------------------------
+ | data | |
+ --------------------------------------------
+ ^ ^
+ Start of assembled packet
+
+ Packet construct is as follows (* = won't be encrypted):
+
+ x bytes SILC Header
+ 2 bytes Payload length (*)
+ 1 byte Flags (*)
+ 1 byte Packet type
+ 1 byte Source ID Type
+ 2 bytes Source ID Length
+ x bytes Source ID
+ 1 byte Destination ID Type
+ 2 bytes Destination ID Length
+ x bytes Destination ID
+
+ 1 - 16 bytes Padding
+
+ x bytes Data payload
+
+ All fields in the packet will be authenticated by MAC. The MAC is
+ not computed here, it must be computed differently before encrypting
+ the packet.
+
+*/
+
+void silc_packet_assemble(SilcPacketContext *ctx)
+{
+ unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
+ int i;
+
+ SILC_LOG_DEBUG(("Assembling outgoing packet"));
+
+ /* Get the true length of the packet. This is saved as payload length
+ into the packet header. This does not include the length of the
+ padding. */
+ if (!ctx->truelen)
+ ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN +
+ ctx->src_id_len + ctx->dst_id_len;
+
+ /* Calculate the length of the padding. The padding is calculated from
+ the data that will be encrypted. As protocol states 3 first bytes
+ of the packet are not encrypted they are not included in the
+ padding calculation. */
+ if (!ctx->padlen)
+ ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+
+ /* Put the start of the data section to the right place. */
+ silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN +
+ ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+
+ /* Get random padding */
+#if 1
+ for (i = 0; i < ctx->padlen; i++)
+ tmppad[i] = silc_rng_get_byte(ctx->rng);
+#else
+ /* XXX: For testing - to be removed */
+ memset(tmppad, 65, sizeof(tmppad));
+#endif
+
+ /* Create the packet. This creates the SILC header and adds padding,
+ rest of the buffer remains as it is. */
+ silc_buffer_format(ctx->buffer,
+ SILC_STR_UI_SHORT(ctx->truelen),
+ SILC_STR_UI_CHAR(ctx->flags),
+ SILC_STR_UI_CHAR(ctx->type),
+ SILC_STR_UI_SHORT(ctx->src_id_len),
+ SILC_STR_UI_SHORT(ctx->dst_id_len),
+ SILC_STR_UI_CHAR(ctx->src_id_type),
+ SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
+ SILC_STR_UI_CHAR(ctx->dst_id_type),
+ SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
+ SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
+ SILC_STR_END);
+
+ SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len),
+ ctx->buffer->data, ctx->buffer->len);
+
+ SILC_LOG_DEBUG(("Outgoing packet assembled"));
+}
--- /dev/null
+/*
+
+ silcpacket.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPACKET_H
+#define SILCPACKET_H
+
+/* Amount of bytes to be read from the socket connection at once. */
+#define SILC_PACKET_READ_SIZE 16384
+
+/* Default byte size of the packet. This can be set larger if this
+ is not enough, we shall see. */
+#define SILC_PACKET_DEFAULT_SIZE 2048
+
+/* Header length without source and destination ID's. */
+#define SILC_PACKET_HEADER_LEN 8 + 2
+
+/* Minimum length of SILC Packet Header. This much is decrypted always
+ when packet is received to be able to get all the relevant data out
+ from the header. */
+#define SILC_PACKET_MIN_HEADER_LEN 16 + 2
+
+/* Maximum padding length */
+#define SILC_PACKET_MAX_PADLEN 16
+
+/* Minimum packet length */
+#define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
+
+/* Maximum length of ID */
+#define SILC_PACKET_MAX_ID_LEN 16
+
+/* SILC packet type definition. For now, it is defined like this and I don't
+ expect it to change in any near future. If one byte as a packet type is
+ not enough we can, then, think something else. */
+typedef unsigned char SilcPacketType;
+
+/* SILC packet version type definition. */
+typedef unsigned char SilcPacketVersion;
+
+/* SILC packet flags type definition. */
+typedef unsigned char SilcPacketFlags;
+
+/* All defined packet flags */
+#define SILC_PACKET_FLAG_NONE 0x00
+#define SILC_PACKET_FLAG_PRIVMSG_KEY 0x01
+#define SILC_PACKET_FLAG_FORWARDED 0x02 /* XXX deprecated 26062000 */
+#define SILC_PACKET_FLAG_BROADCAST 0x04
+/* Rest of flags still available
+#define SILC_PACKET_FLAG_XXX 0x08
+#define SILC_PACKET_FLAG_XXX 0x10
+#define SILC_PACKET_FLAG_XXX 0x20
+#define SILC_PACKET_FLAG_XXX 0x40
+#define SILC_PACKET_FLAG_XXX 0x80
+*/
+
+/*
+ SILC packet context.
+
+ In packet sending this is filled and sent to silc_packet_assemble
+ which then uses it to assemble new packet. In packet reception pointer
+ to this context is sent to silc_packet_parse which parses the packet
+ and returns the relevant information to this structure. On packet
+ reception returned ID's are always the hash values of the ID's from
+ the packet.
+
+ Short description of the fields following:
+
+ SilcBuffer buffer
+
+ The data buffer.
+
+ SilcPacketType type
+
+ Type of the packet. Types are defined below.
+
+ SilcPacketFlags flags
+
+ Packet flags. Flags are defined above.
+
+ unsigned char *src_id
+ unsigned int src_id_len
+ SilcIdType src_id_type
+
+ Source ID, its length and type. On packet reception retuned ID's
+ are always the hash values of the ID's from the packet.
+
+ SilcHash hash
+
+ Pointer to allocated hash object. This must be MD5 hash object.
+ This is used to calculate checksum of the packet.
+
+*/
+typedef struct {
+ SilcBuffer buffer;
+ SilcPacketType type;
+ SilcPacketFlags flags;
+
+ unsigned char *src_id;
+ unsigned int src_id_len;
+ SilcIdType src_id_type;
+
+ unsigned char *dst_id;
+ unsigned int dst_id_len;
+ SilcIdType dst_id_type;
+
+ unsigned int truelen;
+ unsigned int padlen;
+
+ /* For padding generation */
+ SilcRng rng;
+} SilcPacketContext;
+
+/* SILC Packet types. */
+#define SILC_PACKET_NONE 0 /* NULL, never sent */
+#define SILC_PACKET_DISCONNECT 1 /* Disconnection */
+#define SILC_PACKET_SUCCESS 2 /* Success */
+#define SILC_PACKET_FAILURE 3 /* Failure */
+#define SILC_PACKET_REJECT 4 /* Rejected */
+#define SILC_PACKET_NOTIFY 5 /* Notify message */
+#define SILC_PACKET_ERROR 6 /* Error message */
+#define SILC_PACKET_CHANNEL_MESSAGE 7 /* Message for channel */
+#define SILC_PACKET_CHANNEL_KEY 8 /* Key of the channel */
+#define SILC_PACKET_PRIVATE_MESSAGE 9 /* Private message */
+#define SILC_PACKET_PRIVATE_MESSAGE_KEY 10 /* Private message key*/
+#define SILC_PACKET_COMMAND 11 /* Command */
+#define SILC_PACKET_COMMAND_REPLY 12 /* Reply to a command */
+#define SILC_PACKET_KEY_EXCHANGE 13 /* Start of KE */
+#define SILC_PACKET_KEY_EXCHANGE_1 14 /* KE1 */
+#define SILC_PACKET_KEY_EXCHANGE_2 15 /* KE2 */
+#define SILC_PACKET_CONNECTION_AUTH_REQUEST 16 /* Request of auth meth */
+#define SILC_PACKET_CONNECTION_AUTH 17 /* Connectinon auth */
+#define SILC_PACKET_NEW_ID 18 /* Sending new ID */
+#define SILC_PACKET_NEW_ID_LIST 19 /* Sending list of them */
+#define SILC_PACKET_NEW_CLIENT 20 /* Registering client */
+#define SILC_PACKET_NEW_SERVER 21 /* Registering server */
+#define SILC_PACKET_NEW_CHANNEL 22 /* Registering channel */
+#define SILC_PACKET_NEW_CHANNEL_USER 23 /* "" user on channel */
+#define SILC_PACKET_NEW_CHANNEL_LIST 24 /* List of new channels */
+#define SILC_PACKET_NEW_CHANNEL_USER_LIST 25 /* List of users on "" */
+#define SILC_PACKET_REPLACE_ID 26 /* To replace old ID */
+#define SILC_PACKET_REMOVE_ID 27 /* To remove ID */
+/* #define SILC_PACKET_MAX 255 */
+
+/* Macros */
+
+/* Returns true length of the packet and padded length of the packet */
+#define SILC_PACKET_LENGTH(__packet, __ret_truelen, __ret_padlen) \
+do { \
+ SILC_GET16_MSB((__ret_truelen), (__packet)->data); \
+ (__ret_padlen) = (((__ret_truelen) - 2) + \
+ SILC_PACKET_MAX_PADLEN) & ~(SILC_PACKET_MAX_PADLEN - 1); \
+} while(0)
+
+/* Returns pad length of the packet */
+#define SILC_PACKET_PADLEN(__packetlen) \
+ SILC_PACKET_MAX_PADLEN - ((__packetlen) - 2) % SILC_PACKET_MAX_PADLEN;
+
+/* Prototypes */
+int silc_packet_write(int sock, SilcBuffer src);
+int silc_packet_read(int sock, SilcBuffer dest);
+void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
+ unsigned int len);
+void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer,
+ unsigned int len);
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx);
+void silc_packet_assemble(SilcPacketContext *ctx);
+
+#endif
--- /dev/null
+/*
+
+ silcprotocol.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Created: Tue Nov 25 19:25:33 GMT+0200 1997
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcprotocol.h"
+
+/* Allocates a new protocol object. The new allocated and initialized
+ protocol is returned to the new_protocol argument. The argument context
+ is the context to be sent as argument for the protocol. The callback
+ argument is the function to be called _after_ the protocol has finished. */
+
+void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
+ void *context, SilcProtocolFinalCallback callback)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Allocating new protocol type %d", type));
+
+ for (i = 0; silc_protocol_list[i].callback; i++)
+ if (silc_protocol_list[i].type == type)
+ break;
+
+ if (!silc_protocol_list[i].callback) {
+ SILC_LOG_ERROR(("Requested protocol does not exists"));
+ return;
+ }
+
+ *new_protocol = silc_calloc(1, sizeof(**new_protocol));
+ if (*new_protocol == NULL) {
+ SILC_LOG_ERROR(("Cannot allocate new protocol object"));
+ return;
+ }
+
+ (*new_protocol)->protocol = (SilcProtocolObject *)&silc_protocol_list[i];
+ (*new_protocol)->state = SILC_PROTOCOL_STATE_UNKNOWN;
+ (*new_protocol)->context = context;
+ (*new_protocol)->execute = silc_protocol_execute;
+ (*new_protocol)->execute_final = silc_protocol_execute_final;
+ (*new_protocol)->final_callback = callback;
+}
+
+/* Free's a protocol object. */
+
+void silc_protocol_free(SilcProtocol protocol)
+{
+ if (protocol)
+ silc_free(protocol);
+}
+
+/* Executes next state of the protocol. The state must be set before
+ calling this function. */
+
+void silc_protocol_execute(void *qptr, int type,
+ void *context, int fd,
+ long secs, long usecs)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (secs + usecs)
+ silc_task_register(qptr, fd, protocol->protocol->callback, context,
+ secs, usecs,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ else
+ protocol->protocol->callback(qptr, 0, context, fd);
+}
+
+/* Executes the final callback of the protocol. */
+
+void silc_protocol_execute_final(void *qptr, int type,
+ void *context, int fd)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+
+ SILC_LOG_DEBUG(("Start, state=%d", protocol->state));
+
+ protocol->final_callback(qptr, 0, context, fd);
+}
--- /dev/null
+/*
+
+ silcprotocol.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPROTOCOL_H
+#define SILCPROTOCOL_H
+
+/* Protocol type definition. */
+typedef unsigned char SilcProtocolType;
+
+/* Protocol state definition. */
+typedef unsigned char SilcProtocolState;
+
+/* Protocol states. Do NOT change the values of these states, especially
+ the START state or you break every protocol. */
+#define SILC_PROTOCOL_STATE_UNKNOWN 0
+#define SILC_PROTOCOL_STATE_START 1
+#define SILC_PROTOCOL_STATE_END 253
+#define SILC_PROTOCOL_STATE_ERROR 254
+
+/* Connection Authentication protocols' authentication methods */
+#define SILC_PROTOCOL_CONN_AUTH_NONE 0
+#define SILC_PROTOCOL_CONN_AUTH_PASSWORD 1
+#define SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY 2
+
+/*
+ SILC Protocol Object.
+
+ Short description of the field following:
+
+ SilcProtocolType type
+
+ Protocol type. This is enumeration.
+
+ SilcProtocolCallback callback;
+
+ Callback function for the protocol. This is SilcTaskCallback function
+ pointer as the protocols in SILC are executed as timeout tasks.
+
+ The object expands to another structure as well. Short description of
+ these fields following:
+
+ SilcProtocolObject *protocol
+
+ This is the pointer to the protocol object defined above.
+
+ SilcProtocolState state
+
+ Protocol state. This is enumeration. The state of the protocol can
+ be changed in the callback function.
+
+ void *context
+
+ Context to be sent for the callback function. This is usually
+ object for either SILC client or server. However, this abstraction
+ makes it possible that this pointer could be some other object as well.
+
+ SilcProtocolExecute execute;
+
+ Executes the protocol and its states. The correct state must be set
+ before calling this function. The state is usually set in the protocol
+ specific routines.
+
+ SilcProtocolExecute execute_final;
+
+ Executes the final callback function of the protocol. Read on.
+
+ SilcProtocolFinalCallback final_callback;
+
+ This is a callback function that is called with timeout _after_ the
+ protocol has finished or error occurs. If this is NULL, naturally
+ nothing will be executed. Protocol should call this function only at
+ SILC_PROTOCOL_STATE_END and SILC_PROTOCOL_STATE_ERROR states.
+
+*/
+typedef SilcTaskCallback SilcProtocolCallback;
+
+typedef struct {
+ SilcProtocolType type;
+ SilcProtocolCallback callback;
+} SilcProtocolObject;
+
+typedef SilcTaskCallback SilcProtocolFinalCallback;
+typedef SilcTaskCallback SilcProtocolExecute;
+
+typedef struct SilcProtocolObjectStruct {
+ SilcProtocolObject *protocol;
+ SilcProtocolState state;
+ void *context;
+
+ // SilcProtocolExecute execute;
+ void (*execute)(void *, int, void *, int, long, long);
+ SilcProtocolExecute execute_final;
+ SilcProtocolFinalCallback final_callback;
+} *SilcProtocol;
+
+/* Definition for SILC protocol list. This list includes all the
+ protocols in the SILC. SILC server and client defined own list of
+ protocols. */
+extern const SilcProtocolObject silc_protocol_list[];
+
+/* Prototypes */
+void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
+ void *context, SilcProtocolFinalCallback callback);
+void silc_protocol_free(SilcProtocol protocol);
+void silc_protocol_execute(void *qptr, int type,
+ void *context, int fd,
+ long secs, long usecs);
+void silc_protocol_execute_final(void *qptr, int type,
+ void *context, int fd);
+
+#endif
--- /dev/null
+/*
+
+ silcschedule.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1998 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* The actual schedule object. */
+static SilcSchedule schedule;
+
+/* Initializes the schedule. Sets the non-timeout task queue hook and
+ the timeout task queue hook. This must be called before the schedule
+ is able to work. */
+
+void silc_schedule_init(SilcTaskQueue fd_queue,
+ SilcTaskQueue timeout_queue,
+ SilcTaskQueue generic_queue,
+ int max_fd)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Initializing scheduler"));
+
+ /* Initialize the schedule */
+ memset(&schedule, 0, sizeof(schedule));
+ schedule.fd_queue = fd_queue;
+ schedule.timeout_queue = timeout_queue;
+ schedule.generic_queue = generic_queue;
+ schedule.fd_list.fd = silc_calloc(max_fd, sizeof(int));
+ schedule.fd_list.last_fd = 0;
+ schedule.fd_list.max_fd = max_fd;
+ schedule.timeout = NULL;
+ schedule.valid = TRUE;
+ FD_ZERO(&schedule.in);
+ FD_ZERO(&schedule.out);
+ schedule.max_fd = -1;
+ for (i = 0; i < max_fd; i++)
+ schedule.fd_list.fd[i] = -1;
+}
+
+/* Uninitializes the schedule. This is called when the program is ready
+ to end. This removes all tasks and task queues. */
+
+int silc_schedule_uninit()
+{
+
+ SILC_LOG_DEBUG(("Uninitializing scheduler"));
+
+ if (schedule.valid == TRUE)
+ return FALSE;
+
+ /* Unregister all tasks */
+ if (schedule.fd_queue)
+ silc_task_remove(schedule.fd_queue, SILC_ALL_TASKS);
+ if (schedule.timeout_queue)
+ silc_task_remove(schedule.timeout_queue, SILC_ALL_TASKS);
+ if (schedule.generic_queue)
+ silc_task_remove(schedule.generic_queue, SILC_ALL_TASKS);
+
+ /* Unregister all task queues */
+ if (schedule.fd_queue)
+ silc_task_queue_free(schedule.fd_queue);
+ if (schedule.timeout_queue)
+ silc_task_queue_free(schedule.timeout_queue);
+ if (schedule.generic_queue)
+ silc_task_queue_free(schedule.generic_queue);
+
+ /* Clear the fd list */
+ if (schedule.fd_list.fd) {
+ memset(schedule.fd_list.fd, -1, schedule.fd_list.max_fd);
+ silc_free(schedule.fd_list.fd);
+ }
+
+ memset(&schedule, 'F', sizeof(schedule));
+ return TRUE;
+}
+
+/* Stops the schedule even if it is not supposed to be stopped yet.
+ After calling this, one should call silc_schedule_uninit (after the
+ silc_schedule has returned). */
+
+void silc_schedule_stop()
+{
+ SILC_LOG_DEBUG(("Stopping scheduler"));
+
+ if (schedule.valid == TRUE)
+ schedule.valid = FALSE;
+}
+
+/* Sets a file descriptor to be listened by select() in scheduler. One can
+ call this directly if wanted. This can be called multiple times for
+ one file descriptor to set different iomasks. */
+
+void silc_schedule_set_listen_fd(int fd, unsigned int iomask)
+{
+ assert(schedule.valid != FALSE);
+ assert(fd < schedule.fd_list.max_fd);
+
+ schedule.fd_list.fd[fd] = iomask;
+
+ if (fd > schedule.fd_list.last_fd)
+ schedule.fd_list.last_fd = fd;
+}
+
+/* Removes a file descriptor from listen list. */
+
+void silc_schedule_unset_listen_fd(int fd)
+{
+ assert(schedule.valid != FALSE);
+ assert(fd < schedule.fd_list.max_fd);
+
+ schedule.fd_list.fd[fd] = -1;
+
+ if (fd == schedule.fd_list.last_fd) {
+ int i;
+
+ for (i = fd; i >= 0; i--)
+ if (schedule.fd_list.fd[i] != -1)
+ break;
+
+ schedule.fd_list.last_fd = i;
+ }
+}
+
+/* Executes tasks matching the file descriptor set by select(). The task
+ remains on the task queue after execution. Invalid tasks are removed
+ here from the task queue. This macro is used by silc_schedule function.
+ We don't have to care about the tasks priority here because the tasks
+ are sorted in their priority order already at the registration phase. */
+
+#define SILC_SCHEDULE_RUN_TASKS \
+do { \
+ queue = schedule.fd_queue; \
+ if (queue && queue->valid == TRUE && queue->task) { \
+ task = queue->task; \
+ \
+ /* Walk thorugh all tasks in the particular task queue and \
+ execute the callback functions of those tasks matching the \
+ fd set by select(). */ \
+ while(1) { \
+ /* Validity of the task is checked always before and after \
+ execution beacuse the task might have been unregistered \
+ in the callback function, ie. it is not valid anymore. */ \
+ \
+ if (task->valid) { \
+ /* Task ready for reading */ \
+ if ((FD_ISSET(task->fd, &schedule.in)) && \
+ (task->iomask & (1L << SILC_TASK_READ))) { \
+ task->callback(queue, SILC_TASK_READ, task->context, task->fd); \
+ is_run = TRUE; \
+ } \
+ } \
+ \
+ if (task->valid) { \
+ /* Task ready for writing */ \
+ if ((FD_ISSET(task->fd, &schedule.out)) && \
+ (task->iomask & (1L << SILC_TASK_WRITE))) { \
+ task->callback(queue, SILC_TASK_WRITE, task->context, task->fd); \
+ is_run = TRUE; \
+ } \
+ } \
+ \
+ if (!task->valid) { \
+ /* Invalid (unregistered) tasks are removed from the \
+ task queue. */ \
+ if (queue->task == task->next) { \
+ silc_task_remove(queue, task); \
+ break; \
+ } \
+ \
+ task = task->next; \
+ silc_task_remove(queue, task->prev); \
+ continue; \
+ } \
+ \
+ /* Break if there isn't more tasks in the queue */ \
+ if (queue->task == task->next) \
+ break; \
+ \
+ task = task->next; \
+ } \
+ } \
+} while(0)
+
+/* Selects tasks to be listened by select(). These are the non-timeout
+ tasks. This checks the scheduler's fd list. This macro is used by
+ silc_schedule function. */
+
+#define SILC_SCHEDULE_SELECT_TASKS \
+do { \
+ for (i = 0; i <= schedule.fd_list.last_fd; i++) { \
+ if (schedule.fd_list.fd[i] != -1) { \
+ \
+ /* Set the max fd value for select() to listen */ \
+ if (i > schedule.max_fd) \
+ schedule.max_fd = i; \
+ \
+ /* Add tasks for reading */ \
+ if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_READ))) \
+ FD_SET(i, &schedule.in); \
+ \
+ /* Add tasks for writing */ \
+ if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_WRITE))) \
+ FD_SET(i, &schedule.out); \
+ } \
+ } \
+} while(0)
+
+/* Executes all tasks whose timeout has expired. The task is removed from
+ the task queue after the callback function has returned. Also, invalid
+ tasks are removed here. The current time must be get before calling this
+ macro. This macro is used by silc_schedule function. We don't have to
+ care about priorities because tasks are already sorted in their priority
+ order at the registration phase. */
+
+#define SILC_SCHEDULE_RUN_TIMEOUT_TASKS \
+do { \
+ queue = schedule.timeout_queue; \
+ if (queue && queue->valid == TRUE && queue->task) { \
+ task = queue->task; \
+ \
+ /* Walk thorugh all tasks in the particular task queue \
+ and run all the expired tasks. */ \
+ while(1) { \
+ /* Execute the task if the timeout has expired */ \
+ if (silc_task_timeout_compare(&task->timeout, &curtime)) { \
+ \
+ /* Task ready for reading */ \
+ if (task->valid) { \
+ if ((task->iomask & (1L << SILC_TASK_READ))) \
+ task->callback(queue, SILC_TASK_READ, \
+ task->context, task->fd); \
+ } \
+ \
+ /* Task ready for writing */ \
+ if (task->valid) { \
+ if ((task->iomask & (1L << SILC_TASK_WRITE))) \
+ task->callback(queue, SILC_TASK_WRITE, \
+ task->context, task->fd); \
+ } \
+ \
+ /* Break if there isn't more tasks in the queue */ \
+ if (queue->task == task->next) { \
+ /* Remove the task from queue */ \
+ silc_task_remove(queue, task); \
+ break; \
+ } \
+ \
+ task = task->next; \
+ \
+ /* Remove the task from queue */ \
+ silc_task_remove(queue, task->prev); \
+ } else { \
+ /* The timeout hasn't expired, check for next one */ \
+ \
+ /* Break if there isn't more tasks in the queue */ \
+ if (queue->task == task->next) \
+ break; \
+ \
+ task = task->next; \
+ } \
+ } \
+ } \
+} while(0)
+
+/* Calculates next timeout for select(). This is the timeout value
+ when at earliest some of the timeout tasks expire. If this is in the
+ past, they will be run now. This macro is used by the silc_schedule
+ function. */
+
+#define SILC_SCHEDULE_SELECT_TIMEOUT \
+do { \
+ if (schedule.timeout_queue && schedule.timeout_queue->valid == TRUE) { \
+ queue = schedule.timeout_queue; \
+ task = NULL; \
+ \
+ /* Get the current time */ \
+ gettimeofday(&curtime, NULL); \
+ schedule.timeout = NULL; \
+ \
+ /* First task in the task queue has always the smallest timeout. */ \
+ task = queue->task; \
+ while(1) { \
+ if (task && task->valid == TRUE) { \
+ \
+ /* If the timeout is in past, we will run the task and all other \
+ timeout tasks from the past. */ \
+ if (silc_task_timeout_compare(&task->timeout, &curtime)) { \
+ SILC_SCHEDULE_RUN_TIMEOUT_TASKS; \
+ \
+ /* The task(s) has expired and doesn't exist on the task queue \
+ anymore. We continue with new timeout. */ \
+ queue = schedule.timeout_queue; \
+ task = queue->task; \
+ if (task == NULL || task->valid == FALSE) \
+ break; \
+ goto cont; \
+ } else { \
+ cont: \
+ /* Calculate the next timeout for select() */ \
+ queue->timeout.tv_sec = task->timeout.tv_sec - curtime.tv_sec; \
+ queue->timeout.tv_usec = task->timeout.tv_usec - curtime.tv_usec; \
+ \
+ /* We wouldn't want to go under zero, check for it. */ \
+ if (queue->timeout.tv_usec < 0) { \
+ queue->timeout.tv_sec -= 1; \
+ queue->timeout.tv_usec += 1000000L; \
+ } \
+ } \
+ /* We've got the timeout value */ \
+ break; \
+ } else { \
+ /* Task is not valid, remove it and try next one. */ \
+ silc_task_remove(queue, task); \
+ task = queue->task; \
+ if (queue->task == NULL) \
+ break; \
+ } \
+ } \
+ /* Save the timeout */ \
+ if (task) \
+ schedule.timeout = &queue->timeout; \
+ } \
+} while(0)
+
+/* Execute generic tasks. These are executed only and only if for the
+ specific fd there wasn't other non-timeout tasks. This checks the earlier
+ set fd list, thus the generic tasks apply to all specified fd's. All the
+ generic tasks are executed at once. */
+
+#define SILC_SCHEDULE_RUN_GENERIC_TASKS \
+do { \
+ if (is_run == FALSE) { \
+ SILC_LOG_DEBUG(("Running generic tasks")); \
+ for (i = 0; i <= schedule.fd_list.last_fd; i++) \
+ if (schedule.fd_list.fd[i] != -1) { \
+ \
+ /* Check whether this fd is select()ed. */ \
+ if ((FD_ISSET(i, &schedule.in)) || (FD_ISSET(i, &schedule.out))) { \
+ \
+ /* It was selected. Now find the tasks from task queue and execute \
+ all generic tasks. */ \
+ if (schedule.generic_queue && schedule.generic_queue->valid) { \
+ queue = schedule.generic_queue; \
+ \
+ if (!queue->task) \
+ break; \
+ \
+ task = queue->task; \
+ \
+ while(1) { \
+ /* Validity of the task is checked always before and after \
+ execution beacuse the task might have been unregistered \
+ in the callback function, ie. it is not valid anymore. */ \
+ \
+ if (task->valid && schedule.fd_list.fd[i] != -1) { \
+ /* Task ready for reading */ \
+ if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_READ))) \
+ task->callback(queue, SILC_TASK_READ, \
+ task->context, i); \
+ } \
+ \
+ if (task->valid && schedule.fd_list.fd[i] != -1) { \
+ /* Task ready for writing */ \
+ if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_WRITE))) \
+ task->callback(queue, SILC_TASK_WRITE, \
+ task->context, i); \
+ } \
+ \
+ if (!task->valid) { \
+ /* Invalid (unregistered) tasks are removed from the \
+ task queue. */ \
+ if (queue->task == task->next) { \
+ silc_task_remove(queue, task); \
+ break; \
+ } \
+ \
+ task = task->next; \
+ silc_task_remove(queue, task->prev); \
+ continue; \
+ } \
+ \
+ /* Break if there isn't more tasks in the queue */ \
+ if (queue->task == task->next) \
+ break; \
+ \
+ task = task->next; \
+ } \
+ } \
+ } \
+ } \
+ } \
+} while(0)
+
+/* The SILC scheduler. This is actually the main routine in SILC programs.
+ When this returns the program is to be ended. Before this function can
+ be called, one must call silc_schedule_init function. */
+
+void silc_schedule()
+{
+ int is_run, i;
+ SilcTask task;
+ SilcTaskQueue queue;
+ struct timeval curtime;
+
+ SILC_LOG_DEBUG(("Running scheduler"));
+
+ if (schedule.valid == FALSE) {
+ SILC_LOG_ERROR(("Scheduler is not valid, stopping"));
+ return;
+ }
+
+ /* Start the scheduler loop */
+ while(1) {
+
+ SILC_LOG_DEBUG(("In scheduler loop"));
+
+ /* If the task queues aren't initialized or we aren't valid anymore
+ we will return */
+ if ((!schedule.fd_queue && !schedule.timeout_queue
+ && !schedule.generic_queue) || schedule.valid == FALSE) {
+ SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
+ break;
+ }
+
+ /* Clear everything */
+ FD_ZERO(&schedule.in);
+ FD_ZERO(&schedule.out);
+ schedule.max_fd = -1;
+ is_run = FALSE;
+
+ /* Calculate next timeout for select(). This is the timeout value
+ when at earliest some of the timeout tasks expire. */
+ SILC_SCHEDULE_SELECT_TIMEOUT;
+
+ /* Add the file descriptors to the fd sets. These are the non-timeout
+ tasks. The select() listens to these file descriptors. */
+ SILC_SCHEDULE_SELECT_TASKS;
+
+ if (schedule.max_fd == -1) {
+ SILC_LOG_ERROR(("Nothing to listen, exiting"));
+ break;
+ }
+
+ if (schedule.timeout)
+ SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule.timeout->tv_sec,
+ schedule.timeout->tv_usec));
+
+ /* This is the main select(). The program blocks here until some
+ of the selected file descriptors change status or the selected
+ timeout expires. */
+ SILC_LOG_DEBUG(("Select"));
+ switch(select(schedule.max_fd + 1, &schedule.in,
+ &schedule.out, 0, schedule.timeout)) {
+ case -1:
+ /* Error */
+ SILC_LOG_ERROR(("Error in select(): %s", strerror(errno)));
+ break;
+ case 0:
+ /* Timeout */
+ SILC_LOG_DEBUG(("Running timeout tasks"));
+ gettimeofday(&curtime, NULL);
+ SILC_SCHEDULE_RUN_TIMEOUT_TASKS;
+ break;
+ default:
+ /* There is some data available now */
+ SILC_LOG_DEBUG(("Running non-timeout tasks"));
+ SILC_SCHEDULE_RUN_TASKS;
+
+ SILC_SCHEDULE_RUN_GENERIC_TASKS;
+ break;
+ }
+ }
+}
--- /dev/null
+/*
+
+ silcschedule.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1998 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSCHEDULE_H
+#define SILCSCHEDULE_H
+
+/* Structure holding list of file descriptors, scheduler is supposed to
+ be listenning. The max_fd field is the maximum number of possible file
+ descriptors in the list. This value is set at the initialization
+ of the scheduler and it usually is the maximum number of connections
+ allowed. */
+typedef struct {
+ int *fd;
+ unsigned int last_fd;
+ unsigned int max_fd;
+} SilcScheduleFdList;
+
+/*
+ Silc Schedule object.
+
+ This is the actual schedule object in Silc. Both Silc client and server
+ uses this same scheduler. Actually, this scheduler could be used by any
+ program needing scheduling.
+
+ Following short description of the fields:
+
+ SilcTaskQueue fd_queue
+
+ Task queue hook for non-timeout tasks. Usually this means that these
+ tasks perform different kind of I/O on file descriptors. File
+ descriptors are usually network sockets but they actually can be
+ any file descriptors. This hook is initialized in silc_schedule_init
+ function. Timeout tasks should not be added to this queue because
+ they will never expire.
+
+ SilcTaskQueue timeout_queue
+
+ Task queue hook for timeout tasks. This hook is reserved specificly
+ for tasks with timeout. Non-timeout tasks should not be added to this
+ queue because they will never get scheduled. This hook is also
+ initialized in silc_schedule_init function.
+
+ SilcTaskQueue generic_queue
+
+ Task queue hook for generic tasks. This hook is reserved specificly
+ for generic tasks, tasks that apply to all file descriptors, except
+ to those that have specificly registered a non-timeout task. This hook
+ is also initialized in silc_schedule_init function.
+
+ SilcScheduleFdList fd_list
+
+ List of file descriptors the scheduler is supposed to be listenning.
+ This is updated internally.
+
+ struct timeval *timeout;
+
+ Pointer to the schedules next timeout. Value of this timeout is
+ automatically updated in the silc_schedule function.
+
+ int valid
+
+ Marks validity of the scheduler. This is a boolean value. When this
+ is false the scheduler is terminated and the program will end. This
+ set to true when the scheduler is initialized with silc_schedule_init
+ function.
+
+ fd_set in
+ fd_set out
+
+ File descriptor sets for select(). These are automatically managed
+ by the scheduler and should not be touched otherwise.
+
+ int max_fd
+
+ Number of maximum file descriptors for select(). This, as well, is
+ managed automatically by the scheduler and should be considered to
+ be read-only field otherwise.
+
+*/
+
+typedef struct {
+ SilcTaskQueue fd_queue;
+ SilcTaskQueue timeout_queue;
+ SilcTaskQueue generic_queue;
+ SilcScheduleFdList fd_list;
+ struct timeval *timeout;
+ int valid;
+ fd_set in;
+ fd_set out;
+ int max_fd;
+} SilcScheduleObject;
+
+typedef SilcScheduleObject SilcSchedule;
+
+/* Prototypes */
+void silc_schedule_init(SilcTaskQueue fd_queue,
+ SilcTaskQueue timeout_queue,
+ SilcTaskQueue generic_queue,
+ int max_fd);
+int silc_schedule_uninit();
+void silc_schedule_stop();
+void silc_schedule_set_listen_fd(int fd, unsigned int iomask);
+void silc_schedule_unset_listen_fd(int fd);
+void silc_schedule();
+
+#endif
--- /dev/null
+/*
+
+ silcsockconn.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Allocates a new socket connection object. The allocated object is
+ returned to the new_socket argument. */
+
+void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
+ SilcSocketConnection *new_socket)
+{
+ SILC_LOG_DEBUG(("Allocating new socket connection object"));
+
+ *new_socket = silc_calloc(1, sizeof(**new_socket));
+ if (*new_socket == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new socket connection object"));
+ return;
+ }
+
+ /* Set the pointers. Incoming and outgoing data buffers
+ are allocated by the server when they are first used. */
+ (*new_socket)->sock = sock;
+ (*new_socket)->type = type;
+ (*new_socket)->user_data = user_data;
+ (*new_socket)->protocol = NULL;
+ (*new_socket)->flags = 0;
+ (*new_socket)->inbuf = NULL;
+ (*new_socket)->outbuf = NULL;
+}
+
+/* Free's the Socket connection object. */
+
+void silc_socket_free(SilcSocketConnection sock)
+{
+ if (sock) {
+ // silc_protocol_free(sock->protocol);
+ silc_buffer_free(sock->inbuf);
+ silc_buffer_free(sock->outbuf);
+ silc_free(sock);
+ }
+}
--- /dev/null
+/*
+
+ silcsockconn.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSOCKCONN_H
+#define SILCSOCKCONN_H
+
+/* Socket types. These identifies the socket connection. */
+typedef enum {
+ SILC_SOCKET_TYPE_UNKNOWN = 0,
+ SILC_SOCKET_TYPE_CLIENT = 1,
+ SILC_SOCKET_TYPE_SERVER = 2,
+ SILC_SOCKET_TYPE_ROUTER = 3
+} SilcSocketType;
+
+/* Socket flags */
+#define SILC_SF_NONE 0
+#define SILC_SF_INBUF_PENDING 1
+#define SILC_SF_OUTBUF_PENDING 2
+#define SILC_SF_DISCONNECTING 3
+#define SILC_SF_DISCONNECTED 4
+
+/*
+ SILC Socket Connection object.
+
+ This object holds information about the connected sockets to the server.
+ This is quite important object since this is referenced by the server all
+ the time when figuring out what the connection is supposed to be doing
+ and to whom we should send a message.
+
+ Following short description of the fields:
+
+ int sock
+
+ The actual connected socket. This is usually saved when accepting
+ new connection to the server.
+
+ SilcSocketType type
+
+ Type of the socket. This identifies the type of the connection. This
+ is mainly used to identify whether the connection is a client or a
+ server connection.
+
+ void *user_data
+
+ This is a pointer to a data that is is saved here at the same
+ time a new connection object is allocated. Usually this is a
+ back-pointer to some important data for fast referencing. For
+ SILC server this is a pointer to the ID list and for SILC client
+ to object holding active connections (windows).
+
+ SilcProtocol protocol
+
+ Protocol object for the socket. Currently only one protocol can be
+ executing at a time for a particular socket.
+
+ unsigned int flags
+
+ Socket flags that indicate the status of the socket. This can
+ indicate several different status that can affect the use of the
+ socket object.
+
+ SilcBuffer inbuf
+ SilcBuffer outbuf
+
+ Incoming and outgoing buffers for the particular socket connection.
+ Incoming data from the socket is put after decryption in to the
+ inbuf buffer and outgoing data after encryption is put to the outbuf
+ buffer.
+
+*/
+typedef struct {
+ int sock;
+ SilcSocketType type;
+ void *user_data;
+ SilcProtocol protocol;
+ unsigned int flags;
+
+ char *hostname;
+ char *ip;
+ unsigned short port;
+
+ SilcBuffer inbuf;
+ SilcBuffer outbuf;
+} SilcSocketConnectionObject;
+
+typedef SilcSocketConnectionObject *SilcSocketConnection;
+
+/* Macros */
+
+/* Generic manipulation of flags */
+#define SF_SET(x, f) (x)->flags |= (1L << (f))
+#define SF_UNSET(x, f) (x)->flags &= ~(1L << (f))
+#define SF_IS(x, f) (x)->flags & (1L << (f))
+
+/* Setting/Unsetting flags */
+#define SILC_SET_OUTBUF_PENDING(x) SF_SET((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_SET_INBUF_PENDING(x) SF_SET((x), SILC_SF_INBUF_PENDING)
+#define SILC_SET_DISCONNECTING(x) SF_SET((x), SILC_SF_DISCONNECTING)
+#define SILC_SET_DISCONNECTED(x) SF_SET((x), SILC_SF_DISCONNECTED)
+#define SILC_UNSET_OUTBUF_PENDING(x) SF_UNSET((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_UNSET_INBUF_PENDING(x) SF_UNSET((x), SILC_SF_INBUF_PENDING)
+#define SILC_UNSET_DISCONNECTING(x) SF_UNSET((x), SILC_SF_DISCONNECTING)
+#define SILC_UNSET_DISCONNECTED(x) SF_UNSET((x), SILC_SF_DISCONNECTED)
+
+/* Checking for flags */
+#define SILC_IS_OUTBUF_PENDING(x) SF_IS((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_IS_INBUF_PENDING(x) SF_IS((x), SILC_SF_INBUF_PENDING)
+#define SILC_IS_DISCONNECTING(x) SF_IS((x), SILC_SF_DISCONNECTING)
+#define SILC_IS_DISCONNECTED(x) SF_IS((x), SILC_SF_DISCONNECTED)
+
+/* Prototypes */
+void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
+ SilcSocketConnection *new_socket);
+void silc_socket_free(SilcSocketConnection sock);
+
+#endif
--- /dev/null
+/*
+
+ silctask.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1998 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Allocates a new task queue into the Silc. If 'valid' is TRUE the
+ queue becomes valid task queue. If it is FALSE scheduler will skip
+ the queue. */
+
+void silc_task_queue_alloc(SilcTaskQueue *new, int valid)
+{
+
+ SILC_LOG_DEBUG(("Allocating new task queue"));
+
+ *new = silc_calloc(1, sizeof(**new));
+ if (*new == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new task queue object: %s",
+ strerror(errno)));
+ return;
+ }
+
+ /* Set the pointers */
+ (*new)->valid = valid;
+ (*new)->task = NULL;
+ (*new)->register_task = silc_task_register;
+ (*new)->unregister_task = silc_task_unregister;
+ (*new)->set_iotype = silc_task_set_iotype;
+ (*new)->reset_iotype = silc_task_reset_iotype;
+}
+
+/* Free's a task queue. */
+
+void silc_task_queue_free(SilcTaskQueue old)
+{
+ if (old)
+ silc_free(old);
+}
+
+/* Adds a non-timeout task into the task queue. This function is used
+ by silc_task_register function. Returns a pointer to the registered
+ task. */
+
+SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new,
+ SilcTaskPriority priority)
+{
+ SilcTask task, next, prev;
+
+ /* Take the first task in the queue */
+ task = queue->task;
+
+ switch(priority) {
+ case SILC_TASK_PRI_LOW:
+ /* Lowest priority. The task is added at the end of the list. */
+ prev = task->prev;
+ new->prev = prev;
+ new->next = task;
+ prev->next = new;
+ task->prev = new;
+ break;
+ case SILC_TASK_PRI_NORMAL:
+ /* Normal priority. The task is added before lower priority tasks
+ but after tasks with higher priority. */
+ prev = task->prev;
+ while(prev != task) {
+ if (prev->priority > SILC_TASK_PRI_LOW &&
+ prev->priority <= SILC_TASK_PRI_REALTIME)
+ break;
+ prev = prev->prev;
+ }
+ if (prev == task) {
+ /* There are only lower priorities in the list, we will
+ sit before them and become the first task in the queue. */
+ prev = task->prev;
+ new->prev = prev;
+ new->next = task;
+ task->prev = new;
+ prev->next = new;
+
+ /* We are now the first task in queue */
+ queue->task = new;
+ } else {
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ new->prev = prev;
+ new->next = next;
+ prev->next = new;
+ next->prev = new;
+ }
+ break;
+ case SILC_TASK_PRI_HIGH:
+ /* High priority. The task is added before lower priority tasks
+ but after tasks with higher priority. */
+ prev = task->prev;
+ while(prev != task) {
+ if (prev->priority > SILC_TASK_PRI_NORMAL &&
+ prev->priority <= SILC_TASK_PRI_REALTIME)
+ break;
+ prev = prev->prev;
+ }
+ if (prev == task) {
+ /* There are only lower priorities in the list, we will
+ sit before them and become the first task in the queue. */
+ prev = task->prev;
+ new->prev = prev;
+ new->next = task;
+ task->prev = new;
+ prev->next = new;
+
+ /* We are now the first task in queue */
+ queue->task = new;
+ } else {
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ new->prev = prev;
+ new->next = next;
+ prev->next = new;
+ next->prev = new;
+ }
+ break;
+ case SILC_TASK_PRI_REALTIME:
+ /* Highest priority. The task is added at the head of the list.
+ The last registered task is added to the very head of the list
+ thus we get the LIFO (Last-In-First-Out) order. */
+ prev = task->prev;
+ new->prev = prev;
+ new->next = task;
+ prev->next = new;
+ task->prev = new;
+
+ /* We are the first task in the queue */
+ queue->task = new;
+ break;
+ default:
+ silc_free(new);
+ return NULL;
+ }
+
+ return new;
+}
+
+/* Adds a timeout task into the task queue. This function is used by
+ silc_task_register function. Returns a pointer to the registered
+ task. Timeout tasks are sorted by their timeout value in ascending
+ order. The priority matters if there are more than one task with
+ same timeout. */
+
+SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
+ SilcTaskPriority priority)
+{
+ SilcTask task, prev, next;
+
+ /* Take the first task in the queue */
+ task = queue->task;
+
+ /* Take last task from the list */
+ prev = task->prev;
+
+ switch(priority) {
+ case SILC_TASK_PRI_LOW:
+ /* Lowest priority. The task is added at the end of the list. */
+ while(prev != task) {
+
+ /* If we have longer timeout than with the task head of us
+ we have found our spot. */
+ if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+ break;
+
+ /* If we are equal size of timeout we will be after it. */
+ if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+ break;
+
+ /* We have shorter timeout, compare to next one. */
+ prev = prev->prev;
+ }
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ new->prev = prev;
+ new->next = next;
+ prev->next = new;
+ next->prev = new;
+
+ if (prev == task) {
+ /* Check if we are going to be the first task in the queue */
+ if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+ break;
+ if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+ break;
+
+ /* We are now the first task in queue */
+ queue->task = new;
+ }
+ break;
+ case SILC_TASK_PRI_NORMAL:
+ /* Normal priority. The task is added before lower priority tasks
+ but after tasks with higher priority. */
+ while(prev != task) {
+
+ /* If we have longer timeout than with the task head of us
+ we have found our spot. */
+ if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+ break;
+
+ /* If we are equal size of timeout, priority kicks in place. */
+ if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+ if (prev->priority >= SILC_TASK_PRI_NORMAL)
+ break;
+
+ /* We have shorter timeout or higher priority, compare to next one. */
+ prev = prev->prev;
+ }
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ new->prev = prev;
+ new->next = next;
+ prev->next = new;
+ next->prev = new;
+
+ if (prev == task) {
+ /* Check if we are going to be the first task in the queue */
+ if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+ break;
+ if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+ if (prev->priority >= SILC_TASK_PRI_NORMAL)
+ break;
+
+ /* We are now the first task in queue */
+ queue->task = new;
+ }
+ break;
+ case SILC_TASK_PRI_HIGH:
+ /* High priority. The task is added before lower priority tasks
+ but after tasks with higher priority. */
+ while(prev != task) {
+
+ /* If we have longer timeout than with the task head of us
+ we have found our spot. */
+ if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+ break;
+
+ /* If we are equal size of timeout, priority kicks in place. */
+ if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+ if (prev->priority >= SILC_TASK_PRI_HIGH)
+ break;
+
+ /* We have shorter timeout or higher priority, compare to next one. */
+ prev = prev->prev;
+ }
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ new->prev = prev;
+ new->next = next;
+ prev->next = new;
+ next->prev = new;
+
+ if (prev == task) {
+ /* Check if we are going to be the first task in the queue */
+ if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+ break;
+ if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+ if (prev->priority >= SILC_TASK_PRI_HIGH)
+ break;
+
+ /* We are now the first task in queue */
+ queue->task = new;
+ }
+ break;
+ case SILC_TASK_PRI_REALTIME:
+ /* Highest priority. The task is added at the head of the list.
+ The last registered task is added to the very head of the list
+ thus we get the LIFO (Last-In-First-Out) order. */
+ next = task->next;
+ while(next != task) {
+
+ /* If we have shorter timeout than the next task we've found
+ our spot. */
+ if (silc_task_timeout_compare(&new->timeout, &next->timeout))
+ break;
+
+ /* If we are equal size of timeout we will be first. */
+ if (!silc_task_timeout_compare(&next->timeout, &new->timeout))
+ break;
+
+ /* We have longer timeout, compare to next one. */
+ next = next->next;
+ }
+ /* Found a spot from the list, add the task to the list. */
+ prev = next->prev;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+ next->prev = new;
+
+ if (next == task) {
+ /* Check if we are going to be the first task in the queue */
+ if (silc_task_timeout_compare(&next->timeout, &new->timeout))
+ break;
+
+ /* We are now the first task in queue */
+ queue->task = new;
+ }
+ default:
+ silc_free(new);
+ return NULL;
+ }
+
+ return new;
+}
+
+/* Registers a new task into the task queue. The task becomes valid
+ automatically when it is registered. Returns a pointer to the
+ registered task. */
+
+SilcTask silc_task_register(SilcTaskQueue queue, int fd,
+ SilcTaskCallback cb, void *context,
+ long seconds, long useconds,
+ SilcTaskType type, SilcTaskPriority priority)
+{
+ SilcTask new;
+ int timeout = 0;
+
+ SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d",
+ fd, type, priority));
+
+ /* If the task is generic task, we check whether this task has already
+ been registered. Generic tasks are registered only once and after that
+ the same task applies to all file descriptors to be registered. */
+ if ((type == SILC_TASK_GENERIC) && queue->task) {
+ SilcTask task;
+
+ task = queue->task;
+ while(1) {
+ if ((task->callback == cb) && (task->context == context)) {
+ SILC_LOG_DEBUG(("Found matching generic task, using the match"));
+
+ /* Add the fd to be listened, the task found now applies to this
+ fd as well. */
+ silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
+ return task;
+ }
+
+ if (queue->task == task->next)
+ break;
+
+ task = task->next;
+ }
+ }
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new task object"));
+ return NULL;
+ }
+
+ new->fd = fd;
+ new->context = context;
+ new->callback = cb;
+ new->valid = TRUE;
+ new->priority = priority;
+ new->iomask = (1L << SILC_TASK_READ);
+ new->next = new;
+ new->prev = new;
+
+ /* If the task is non-timeout task we have to tell the scheduler that we
+ would like to have these tasks scheduled at some odd distant future. */
+ if (type != SILC_TASK_TIMEOUT)
+ silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
+
+ /* Create timeout if marked to be timeout task */
+ if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
+ gettimeofday(&new->timeout, NULL);
+ new->timeout.tv_sec += seconds + (useconds / 1000000L);
+ new->timeout.tv_usec += (useconds % 1000000L);
+ if (new->timeout.tv_usec > 999999L) {
+ new->timeout.tv_sec += 1;
+ new->timeout.tv_usec -= 1000000L;
+ }
+ timeout = 1;
+ }
+
+ /* Is this first task of the queue? */
+ if (queue->task == NULL) {
+ queue->task = new;
+ return new;
+ }
+
+ if (timeout)
+ return silc_task_add_timeout(queue, new, priority);
+ else
+ return silc_task_add(queue, new, priority);
+}
+
+/* Removes (unregisters) a task from particular task queue. This function
+ is used internally by scheduler. One should not call this function
+ to unregister tasks, instead silc_task_unregister_task function
+ should be used. */
+
+int silc_task_remove(SilcTaskQueue queue, SilcTask task)
+{
+ SilcTask first, old, next;
+
+ if (!queue || !queue->task)
+ return FALSE;
+
+ first = queue->task;
+
+ /* Unregister all tasks in queue */
+ if (task == SILC_ALL_TASKS) {
+ SILC_LOG_DEBUG(("Removing all tasks at once"));
+ next = first;
+
+ while(1) {
+ next = next->next;
+ silc_free(next->prev);
+ if (next == first)
+ break;
+ }
+
+ queue->task = NULL;
+ return TRUE;
+ }
+
+ SILC_LOG_DEBUG(("Removing task"));
+
+ /* Unregister the task */
+ old = first;
+ while(1) {
+ if (old == task) {
+ SilcTask prev, next;
+
+ prev = old->prev;
+ next = old->next;
+ prev->next = next;
+ next->prev = prev;
+
+ if (prev == old && next == old)
+ queue->task = NULL;
+ if (queue->task == old)
+ queue->task = next;
+
+ silc_free(old);
+ return TRUE;
+ }
+ old = old->next;
+
+ if (old == first)
+ return FALSE;
+ }
+}
+
+/* Unregisters a task from the task queue. This is the unregister_task
+ function pointer in task queue object. One should use this function
+ to unregister tasks. This function invalidates the task. */
+
+void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
+{
+
+ /* Unregister all tasks */
+ if (task == SILC_ALL_TASKS) {
+ SilcTask next;
+ SILC_LOG_DEBUG(("Unregistering all tasks at once"));
+
+ if (queue->task == NULL)
+ return;
+
+ next = queue->task;
+
+ while(1) {
+ if (next->valid)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Unregistering task"));
+
+ /* Unregister the specific task */
+ if (task->valid)
+ task->valid = FALSE;
+}
+
+/* Unregister a task by file descriptor. This invalidates the task. */
+
+void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd)
+{
+ SilcTask next;
+
+ SILC_LOG_DEBUG(("Unregister task by fd"));
+
+ if (queue->task == NULL)
+ return;
+
+ next = queue->task;
+
+ while(1) {
+ if (next->fd == fd)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
+}
+
+/* Sets the I/O mask for the task. Only one I/O type can be set at a
+ time. */
+
+void silc_task_set_iotype(SilcTask task, int type)
+{
+ task->iomask |= (1L << type);
+}
+
+/* Resets the I/O mask to the type sent as argument. */
+
+void silc_task_reset_iotype(SilcTask task, int type)
+{
+ task->iomask = (1L << type);
+}
+
+/* Compare two time values. If the first argument is smaller than the
+ second this function returns TRUE. */
+
+int silc_task_timeout_compare(struct timeval *smaller,
+ struct timeval *bigger)
+{
+ if ((smaller->tv_sec < bigger->tv_sec) ||
+ ((smaller->tv_sec == bigger->tv_sec) &&
+ (smaller->tv_usec < bigger->tv_usec)))
+ return TRUE;
+
+ return FALSE;
+}
--- /dev/null
+/*
+
+ silctask.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1998 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCTASK_H
+#define SILCTASK_H
+
+/*
+ SILC Task object.
+
+ int fd
+
+ File descriptor. This usually is a network socket but can be
+ any file descriptor. On generic tasks, that applies to all file
+ descriptors, this is set to -1.
+
+ struct timeval timeout
+
+ The timeout when this task is supposed to be run. This is defined
+ only if the task is a timeout task.
+
+ void *context;
+
+ Context structure passed to callback function as argument.
+
+ SilcTaskCallback callback
+
+ The callback function Silc scheduler calls when this task is scheduled
+ to be run. First argument is the task queue this task belongs to. This
+ is a void pointer and the task queue has to casted out of it. Second
+ argument is the type of the event just occured inside the scheduler
+ (SILC_TASK_READ or SILC_TASK_WRITE). Third argument is the context
+ structure of the task. Last argument is the file descriptor of the
+ task.
+
+ int valid
+
+ Marks for validity of the task. Task that is not valid scheduler
+ will skip. This is boolean value.
+
+ int priority
+
+ Priority of the task. This field is used internally only and it
+ should not be touched otherwise.
+
+ int iomask
+
+ I/O mask which tells to the scheduler for what kind of I/O this
+ task is ready. If the task is ready for both reading and writing
+ SILC_TASK_READ and SILC_TASK_WRITE are masked into this variable.
+ Masking is done by OR'ing (1 << SILC_TASK_*) values. One can check
+ the mask by AND'ing (1L << SILC_TASK_*) against the mask. At the
+ registering of a new task this mask is set to SILC_TASK_READ by
+ default. If a task doesn't perform reading this value must be
+ reset to SILC_TASK_WRITE. If it performs both reading and writing
+ SILC_TASK_WRITE must be added to the mask. A task must always be
+ ready for at least for one I/O type.
+
+ struct SilcTaskStruct *next
+ struct SilcTaskStruct *prev
+
+ Next and previous task. If the task is first in the list, prev is
+ set to the last task in the list. If the task is last in the list,
+ next is set to the first task in the list (forms a circular list).
+
+*/
+
+typedef void (*SilcTaskCallback)(void *, int, void *, int);
+
+typedef struct SilcTaskStruct {
+ int fd;
+ struct timeval timeout;
+ void *context;
+ SilcTaskCallback callback;
+ int valid;
+ int priority;
+ int iomask;
+
+ struct SilcTaskStruct *next;
+ struct SilcTaskStruct *prev;
+} SilcTaskObject;
+
+typedef SilcTaskObject *SilcTask;
+
+/*
+ SILC Task types.
+
+ SILC has three types of tasks, non-timeout tasks (tasks that perform
+ over file descriptors), timeout tasks and generic tasks (tasks that apply
+ to every file descriptor). This type is sent as argument for the
+ task registering function.
+
+*/
+typedef enum {
+ SILC_TASK_FD,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_GENERIC,
+} SilcTaskType;
+
+/*
+ SILC Task priorities.
+
+ Following description of the priorities uses timeout tasks as example
+ how the priority behaves. However, non-timeout tasks behaves same as
+ timeout tasks with following priorities.
+
+ SILC_TASK_PRI_LOW
+
+ Lowest priority. The task is scheduled to run after its timeout
+ has expired only and only when every other task with higher priority
+ has already been run. For non-timeout tasks this priority behaves
+ same way. Life is not fair for tasks with this priority.
+
+ SILC_TASK_PRI_NORMAL
+
+ Normal priority that is used mostly in Silc. This is priority that
+ should always be used unless you specificly need some other priority.
+ The scheduler will run this task as soon as its timeout has expired.
+ For non-timeout tasks this priority behaves same way. Tasks are run
+ in FIFO (First-In-First-Out) order.
+
+ SILC_TASK_PRI_HIGH
+
+ High priority for important tasks. This priority should be used only
+ for important tasks. Life is very fair for tasks with this priority.
+ These tasks are run as soon as its timeout has expired. They are run
+ before normal or lower tasks, respectively. For non-timeout tasks
+ this priority behaves same way. Tasks are run in FIFO order.
+
+ SILC_TASK_PRI_REALTIME
+
+ Highest priority. This priority should be used very carefully because
+ it can make the scheduler extremely unfair to other tasks. The task
+ will be run as soon as its timeout has expired. The task is run before
+ any other task. It is also quaranteed that the last registered task
+ with this priority is the first task to be run when its timeout
+ expires. Tasks are run in LIFO (Last-In-First-Out) order. To make
+ scheduler fair there should never be more than one task in the queue
+ with this priority. Currently none of the tasks in SILC are important
+ enough to use this priority. For non-timeout tasks this priority
+ behaves same way.
+
+*/
+typedef enum {
+ SILC_TASK_PRI_LOW,
+ SILC_TASK_PRI_NORMAL,
+ SILC_TASK_PRI_HIGH,
+ SILC_TASK_PRI_REALTIME,
+} SilcTaskPriority;
+
+/*
+ SILC Task Queue object.
+
+ Usually there are three task queues in SILC. Tasks with timeouts
+ has their own queue, tasks without timeout has one as well and generic
+ tasks has their own also. Scheduler has timeout queue hooks and
+ non-timeout queue hooks in the scheduler and it does not check for
+ timeouts in non-timeout hooks and vice versa, respectively. Ie. Register
+ timeout queues to their own SilcTaskQueue pointer and non-timeout queues
+ to their own pointer.
+
+ Generic tasks, mentioned earlier, has their own task queue. These tasks
+ are non-timeout tasks and they apply to all file descriptors, except to
+ those that have explicitly registered a non-timeout task. These tasks
+ are there to make it simpler and faster to execute common code that
+ applies to all connections. These are, for example, receiving packets
+ from network and sending packets to network. It doesn't make much sense
+ to register a task that receives a packet from network to every connection
+ when you can have one task that applies to all connections. This is what
+ generic tasks are for. Generic tasks are not bound to any specific file
+ descriptor, however, the correct file descriptor must be passed as
+ argument to task registering function.
+
+ Short description of the field following:
+
+ SilcTask task
+
+ Pointer to the tasks in the queue.
+
+ int valid
+
+ Marks for validity of the queue. If the task queue is not valid
+ scheduler will skip it. This is boolean value.
+
+ struct timeval timeout
+
+ Timeout when earliest some tasks in this queue should expire. The
+ value of this timeout is updated automatically by schedule. This
+ is used only and only if this queue is a timeout queue. For normal
+ task queue this is not defined. This is meant only for internal
+ use and it should be considered to be read-only field.
+
+ SilcTask (*register_task)(SilcTaskQueue, int,
+ SilcTaskCallback, void *,
+ long, long,
+ SilcTaskType,
+ SilcTaskPriority)
+
+ Registers a new task to the task queue. Arguments are as follows:
+
+ SilcTaskQueue queue Queue where the task is to be registered
+ int fd File descriptor
+ SilcTaskCallback cb Callback function to call
+ void *context Context to be passed to callback function
+ long seconds Seconds to timeout
+ long useconds Microseconds to timeout
+ SilcTaskType type Type of the task
+ SilcTaskPriority priority Priority of the task
+
+ The same function is used to register all types of tasks. The type
+ argument tells what type of the task is. Note that when registering
+ non-timeout tasks one should also pass 0 as timeout as timeout will
+ be ignored anyway. Also, note, that one cannot register timeout task
+ with 0 timeout. There cannot be zero timeouts, passing zero means
+ no timeout is used for the task and SILC_TASK_FD_TASK is used as
+ default task type in this case.
+
+ One should be careful not to register timeout tasks to the non-timeout
+ task queue, because they will never expire. As one should not register
+ non-timeout tasks to timeout task queue because they will never get
+ scheduled.
+
+ There is a one distinct difference between timeout and non-timeout
+ tasks when they are executed. Non-timeout tasks remain on the task
+ queue after execution. Timeout tasks, however, are removed from the
+ task queue after they have expired. It is safe to re-register a task
+ in its own callback function. It is also safe to unregister a task
+ in a callback function.
+
+ Generic tasks apply to all file descriptors, however, one still must
+ pass the correct file descriptor to the function when registering
+ generic tasks.
+
+ void (*unregister_task)(SilcTaskQueue, SilcTask)
+
+ Unregisters a task already in the queue. Arguments are as follows:
+
+ SilcTaskQueue queue Queue where from the task is unregistered
+ SilcTask task Task to be unregistered
+
+ The same function is used to unregister timeout and non-timeout
+ tasks. One can also unregister all tasks from the queue by passing
+ SILC_ALL_TASKS as task to the function. It is safe to unregister
+ a task in a callback function.
+
+ void (*set_iotype)(SilcTask, int type)
+
+ Sets the I/O type of the task. The scheduler checks for this value
+ and a task must always have at least one of the I/O types set at
+ all time. When registering new task the type is set by default to
+ SILC_TASK_READ. If the task doesn't perform reading one must reset
+ the value to SILC_TASK_WRITE.
+
+ The type sent as argumenet is masked into the task. If the tasks
+ I/O mask already includes this type this function has no effect.
+ Only one I/O type can be added at once. If the task must perform
+ both reading and writing one must call this function for value
+ SILC_TASK_WRITE as well.
+
+ void (*reset_iotype)(SilcTask, int type)
+
+ Resets the mask to the type sent as argument. Note that this resets
+ the previous values to zero and then adds the type sent as argument.
+ This function can be used to remove one of the types masked earlier
+ to the task.
+
+*/
+
+typedef struct SilcTaskQueueStruct {
+ SilcTask task;
+ int valid;
+ struct timeval timeout;
+
+ /* Method functions */
+ SilcTask (*register_task)(struct SilcTaskQueueStruct *, int,
+ SilcTaskCallback, void *, long, long,
+ SilcTaskType, SilcTaskPriority);
+ void (*unregister_task)(struct SilcTaskQueueStruct *, SilcTask);
+ void (*set_iotype)(SilcTask, int type);
+ void (*reset_iotype)(SilcTask, int type);
+} SilcTaskQueueObject;
+
+typedef SilcTaskQueueObject *SilcTaskQueue;
+
+/* Marks for all tasks in a task queue. This can be passed to
+ unregister_task function to cancel all tasks at once. */
+#define SILC_ALL_TASKS ((SilcTask)1)
+
+/* Marks for all task queues. This can be passed to
+ silc_task_queue_unregister function to cancel all task queues at once. */
+#define SILC_ALL_TASK_QUEUES ((SilcTaskQueue)1)
+
+/* Silc Task event types. One of these are passed to the task callback
+ function from the schedule. These values are also masked into a task
+ so that scheduler knows for what kind of I/O it needs to perform
+ for that task. */
+#define SILC_TASK_READ 0
+#define SILC_TASK_WRITE 1
+
+/* Macros */
+
+/* These can be used instead of calling directly the registering function.
+ XXX: These are not used currently, maybe they should be :) */
+#define SILC_REGISTER_FD_TASK(queue, fd, cb, ctx, pri) \
+ (silc_task_register((queue), (fd), (cb), (ctx), 0, 0, \
+ SILC_TASK_FD, (pri)))
+#define SILC_REGISTER_TIMEOUT_TASK(queue, fd, cb, ctx, sec, usec, pri) \
+ (silc_task_register((queue), (fd), (cb), (ctx), (sec), (usec), \
+ SILC_TASK_TIMEOUT, (pri)))
+#define SILC_REGISTER_GENERIC_TASK(queue, fd, cb, ctx, pri) \
+ (silc_task_register((queue), (fd), (cb), (ctx), 0, 0, \
+ SILC_TASK_GENERIC, (pri)))
+
+/* Generic macro to define task callback functions. This defines a function
+ with name 'func' as a task callback function. */
+#define SILC_TASK_CALLBACK(func) \
+static void func(void *qptr, int type, void *context, int fd)
+
+
+/* Prototypes */
+void silc_task_queue_alloc(SilcTaskQueue *new, int valid);
+void silc_task_queue_free(SilcTaskQueue old);
+SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new,
+ SilcTaskPriority priority);
+SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
+ SilcTaskPriority priority);
+SilcTask silc_task_register(SilcTaskQueue queue, int fd,
+ SilcTaskCallback cb, void *context,
+ long seconds, long useconds,
+ SilcTaskType type,
+ SilcTaskPriority priority);
+int silc_task_remove(SilcTaskQueue queue, SilcTask task);
+void silc_task_unregister(SilcTaskQueue queue, SilcTask task);
+void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd);
+void silc_task_set_iotype(SilcTask task, int type);
+void silc_task_reset_iotype(SilcTask task, int type);
+int silc_task_timeout_compare(struct timeval *smaller,
+ struct timeval *bigger);
+
+#endif
--- /dev/null
+/*
+
+ silcutil.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * These are general utility functions that doesn't belong to any specific
+ * group of routines.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Reads a file to a buffer. The allocated buffer is returned. Length of
+ the file read is returned to the return_len argument. */
+
+char *silc_file_read(const char *filename, int *return_len)
+{
+ int fd;
+ char *buffer;
+ int filelen;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
+ return NULL;
+ }
+
+ filelen = lseek(fd, (off_t)0L, SEEK_END);
+ lseek(fd, (off_t)0L, SEEK_SET);
+
+ if (filelen < 0) {
+ SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
+ return NULL;
+ }
+
+ buffer = silc_calloc(filelen + 1, sizeof(char));
+
+ if ((read(fd, buffer, filelen)) == -1) {
+ memset(buffer, 0, sizeof(buffer));
+ close(fd);
+ SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
+ strerror(errno)));
+ return NULL;
+ }
+
+ close(fd);
+ buffer[filelen] = EOF;
+
+ *return_len = filelen;
+ return buffer;
+}
+
+/* Writes a buffer to the file. */
+
+int silc_file_write(const char *filename, const char *buffer, int len)
+{
+ int fd;
+
+ if ((fd = creat(filename, 0644)) == -1) {
+ SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
+ return -1;
+ }
+
+ if ((write(fd, buffer, len)) == -1) {
+ SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+/* Gets line from a buffer. Stops reading when a newline or EOF occurs.
+ This doesn't remove the newline sign from the destination buffer. The
+ argument begin is returned and should be passed again for the function. */
+
+int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
+{
+ static int start = 0;
+ int i;
+
+ memset(dest, 0, destlen);
+
+ if (begin != start)
+ start = 0;
+
+ i = 0;
+ for ( ; start <= srclen; i++, start++) {
+ if (i > destlen)
+ return -1;
+
+ dest[i] = src[start];
+
+ if (dest[i] == EOF)
+ return EOF;
+
+ if (dest[i] == '\n')
+ break;
+ }
+ start++;
+
+ return start;
+}
+
+/* Checks line for illegal characters. Return -1 when illegal character
+ were found. This is used to check for bad lines when reading data from
+ for example a configuration file. */
+
+int silc_check_line(char *buf)
+{
+ /* Illegal characters in line */
+ if (strchr(buf, '#')) return -1;
+ if (strchr(buf, '\'')) return -1;
+ if (strchr(buf, '\\')) return -1;
+ if (strchr(buf, '\r')) return -1;
+ if (strchr(buf, '\a')) return -1;
+ if (strchr(buf, '\b')) return -1;
+ if (strchr(buf, '\f')) return -1;
+
+ /* Empty line */
+ if (buf[0] == '\n')
+ return -1;
+
+ return 0;
+}
+
+/* Returns current time as string. */
+
+char *silc_get_time()
+{
+ time_t curtime;
+ char *return_time;
+
+ curtime = time(NULL);
+ return_time = ctime(&curtime);
+ return_time[strlen(return_time) - 1] = '\0';
+
+ return return_time;
+}
+
+/* Converts string to capital characters */
+
+char *silc_to_upper(char *string)
+{
+ int i;
+ char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
+
+ for (i = 0; i < strlen(string); i++)
+ ret[i] = toupper(string[i]);
+
+ return ret;
+}
+
+/* Compares two strings. Strings may include wildcards * and ?.
+ Returns TRUE if strings match. */
+
+int silc_string_compare(char *string1, char *string2)
+{
+ int i;
+ int slen1 = strlen(string1);
+ int slen2 = strlen(string2);
+ char *tmpstr1, *tmpstr2;
+
+ if (!string1 || !string2)
+ return FALSE;
+
+ /* See if they are same already */
+ if (!strncmp(string1, string2, strlen(string2)))
+ return TRUE;
+
+ if (slen2 < slen1)
+ if (!strchr(string1, '*'))
+ return FALSE;
+
+ /* Take copies of the original strings as we will change them */
+ tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
+ memcpy(tmpstr1, string1, slen1);
+ tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
+ memcpy(tmpstr2, string2, slen2);
+
+ for (i = 0; i < slen2; i++) {
+
+ /* * wildcard. Only one * wildcard is possible. */
+ if (tmpstr1[i] == '*')
+ if (!strncmp(tmpstr1, tmpstr2, i)) {
+ memset(tmpstr2, 0, slen2);
+ strncpy(tmpstr2, tmpstr1, i);
+ break;
+ }
+
+ /* ? wildcard */
+ if (tmpstr1[i] == '?') {
+ if (!strncmp(tmpstr1, tmpstr2, i)) {
+ if (!(slen1 < i + 1))
+ if (tmpstr1[i + 1] != '?' &&
+ tmpstr1[i + 1] != tmpstr2[i + 1])
+ continue;
+
+ if (!(slen1 < slen2))
+ tmpstr2[i] = '?';
+ }
+#if 0
+ } else {
+ if (strncmp(tmpstr1, tmpstr2, i))
+ strncpy(tmpstr2, string2, slen2);
+#endif
+ }
+ }
+
+ /* if using *, remove it */
+ if (strchr(tmpstr1, '*'))
+ *strchr(tmpstr1, '*') = 0;
+
+ if (!strcmp(tmpstr1, tmpstr2)) {
+ memset(tmpstr1, 0, slen1);
+ memset(tmpstr2, 0, slen2);
+ silc_free(tmpstr1);
+ silc_free(tmpstr2);
+ return TRUE;
+ }
+
+ memset(tmpstr1, 0, slen1);
+ memset(tmpstr2, 0, slen2);
+ silc_free(tmpstr1);
+ silc_free(tmpstr2);
+ return FALSE;
+}
--- /dev/null
+/*
+
+ silcutil.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCUTIL_H
+#define SILCUTIL_H
+
+/* Prototypes */
+char *silc_file_read(const char *filename, int *return_len);
+int silc_file_write(const char *filename, const char *buffer, int len);
+int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin);
+int silc_check_line(char *buf);
+char *silc_get_time();
+char *silc_to_upper(char *string);
+int silc_string_compare(char *string1, char *string2);
+
+#endif
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilccrypt.a
+
+libsilccrypt_a_SOURCES = \
+ none.c \
+ blowfish.c \
+ rc5.c \
+ rc6.c \
+ mars.c \
+ md5.c \
+ rijndael.c \
+ rsa.c \
+ sha1.c \
+ twofish.c \
+ silccipher.c \
+ silchash.c \
+ silchmac.c \
+ silcrng.c \
+ silcpkcs.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccore -I../silcmath -I../silcske \
+ -I../silcsim -I../.. -I../../includes \
+ -I../silcmath/gmp-3.0.1
--- /dev/null
+/*
+ * This implementation was taken from the International Kernel (kerneli)
+ * patch for Linux kernel. The author is unknown to me. This
+ * implementation is under the same license as it is in the kerneli patch.
+ * I've modified it a bit to fit to SILC. -Pekka
+ */
+/*
+ * blowfish.c
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, dis-
+ * tribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the fol-
+ * lowing conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+ * SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABIL-
+ * ITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the authors shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * the authors.
+ *
+ */
+
+#include "silcincludes.h"
+#include "blowfish.h"
+
+static u32 bf_pbox[16 + 2] =
+{
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+ 0x9216d5d9, 0x8979fb1b,
+};
+
+static u32 bf_sbox[256 * 4] =
+{
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+};
+
+/*
+ * Round loop unrolling macros, S is a pointer to a S-Box array
+ * organized in 4 unsigned longs at a row.
+ */
+
+#define GET32_3(x) (((x) & 0xff))
+#define GET32_2(x) (((x) >> (8)) & (0xff))
+#define GET32_1(x) (((x) >> (16)) & (0xff))
+#define GET32_0(x) (((x) >> (24)) & (0xff))
+
+#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \
+ S[512 + GET32_2(x)]) + S[768 + GET32_3(x)])
+
+#define ROUND(a, b, n) b^=P[n];a ^= bf_F(b)
+
+/*
+ * The blowfish encipher, processes 64-bit blocks.
+ * NOTE: This function MUSTN'T respect endianess
+ */
+
+int blowfish_encrypt(BlowfishContext *ctx,
+ u32 *in_blk, u32 *out_blk, int size)
+{
+ u32 yl,yr;
+
+ u32 *P = ctx->P;
+ u32 *S = ctx->S;
+
+ for (; size >= 8; size -= 8) {
+ yl = *(in_blk++);
+ yr = *(in_blk++);
+
+ ROUND(yr, yl, 0);
+ ROUND(yl, yr, 1);
+ ROUND(yr, yl, 2);
+ ROUND(yl, yr, 3);
+ ROUND(yr, yl, 4);
+ ROUND(yl, yr, 5);
+ ROUND(yr, yl, 6);
+ ROUND(yl, yr, 7);
+ ROUND(yr, yl, 8);
+ ROUND(yl, yr, 9);
+ ROUND(yr, yl, 10);
+ ROUND(yl, yr, 11);
+ ROUND(yr, yl, 12);
+ ROUND(yl, yr, 13);
+ ROUND(yr, yl, 14);
+ ROUND(yl, yr, 15);
+
+ /* yl and yr are switched */
+ yl ^= P[16];
+ yr ^= P[17];
+
+ *(out_blk++) = yr;
+ *(out_blk++) = yl;
+ }
+
+ return 0;
+}
+
+int blowfish_decrypt(BlowfishContext *ctx,
+ u32 *in_blk, u32 *out_blk, int size)
+{
+ u32 yl,yr;
+
+ u32 *P = ctx->P;
+ u32 *S = ctx->S;
+
+ for (; size >= 8; size -= 8) {
+ yl = *(in_blk++);
+ yr = *(in_blk++);
+
+ ROUND(yr, yl, 17);
+ ROUND(yl, yr, 16);
+ ROUND(yr, yl, 15);
+ ROUND(yl, yr, 14);
+ ROUND(yr, yl, 13);
+ ROUND(yl, yr, 12);
+ ROUND(yr, yl, 11);
+ ROUND(yl, yr, 10);
+ ROUND(yr, yl, 9);
+ ROUND(yl, yr, 8);
+ ROUND(yr, yl, 7);
+ ROUND(yl, yr, 6);
+ ROUND(yr, yl, 5);
+ ROUND(yl, yr, 4);
+ ROUND(yr, yl, 3);
+ ROUND(yl, yr, 2);
+
+ /* yl and yr are switched */
+ yl ^= P[1];
+ yr ^= P[0];
+
+ *(out_blk++) = yr;
+ *(out_blk++) = yl;
+ }
+
+ return 0;
+}
+
+/* Sets the blowfish S and P boxes for encryption and decryption. */
+
+int blowfish_set_key(BlowfishContext *ctx,
+ unsigned char *key, int keybytes)
+{
+ short i;
+ short j;
+ short count;
+ u32 data[2];
+ u32 temp;
+ u32 *P = ctx->P;
+ u32 *S = ctx->S;
+
+ /* Copy the initialization s-boxes */
+
+ for (i = 0, count = 0; i < 256; i++)
+ for (j = 0; j < 4; j++, count++)
+ S[count] = bf_sbox[count];
+
+ /* Set the p-boxes */
+
+ for (i = 0; i < 16 + 2; i++)
+ P[i] = bf_pbox[i];
+
+ /* Actual subkey generation */
+
+ for (j = 0, i = 0; i < 16 + 2; i++)
+ {
+ temp = (((u32) key[j] << 24) |
+ ((u32) key[(j + 1) % keybytes] << 16) |
+ ((u32) key[(j + 2) % keybytes] << 8) |
+ ((u32) key[(j + 3) % keybytes] ));
+
+ P[i] = P[i] ^ temp;
+ j = (j + 4) % keybytes;
+ }
+
+ data[0] = 0x00000000;
+ data[1] = 0x00000000;
+
+ for (i = 0; i < 16 + 2; i += 2)
+ {
+ blowfish_encrypt(ctx, data, data, 8);
+
+ P[i] = data[0];
+ P[i + 1] = data[1];
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0, count = i * 256; j < 256; j += 2, count += 2)
+ {
+ blowfish_encrypt(ctx, data, data, 8);
+
+ S[count] = data[0];
+ S[count + 1] = data[1];
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+
+ blowfish.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef BLOWFISH_H
+#define BLOWFISH_H
+
+#include "blowfish_internal.h"
+
+/*
+ * SILC Crypto API for Blowfish
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(blowfish)
+{
+ blowfish_set_key((BlowfishContext *)context,
+ (unsigned char *)key, keylen);
+ return TRUE;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(blowfish)
+{
+ SilcHash hash;
+ unsigned char key[16];
+
+ silc_hash_alloc("md5", &hash);
+ hash->make_hash(hash, string, stringlen, key);
+
+ blowfish_set_key((BlowfishContext *)context, key, sizeof(key));
+
+ silc_hash_free(hash);
+ memset(&key, 'F', sizeof(key));
+
+ return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(blowfish)
+{
+ return sizeof(BlowfishContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(blowfish)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ blowfish_encrypt((BlowfishContext *)context, tmp, out, 16);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ blowfish_encrypt((BlowfishContext *)context, tmp, out, 16);
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_DECRYPT_CBC(blowfish)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ blowfish_decrypt((BlowfishContext *)context, in, out, 16);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ blowfish_decrypt((BlowfishContext *)context, in, out, 16);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+
+ blowfish_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef BLOWFISH_INTERNAL_H
+#define BLOWFISH_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct blow_key
+{
+ u32 P[18];
+ u32 S[1024];
+} BlowfishContext;
+
+/* Prototypes */
+int blowfish_encrypt(BlowfishContext *ctx,
+ u32 *in_blk, u32 *out_blk, int size);
+int blowfish_decrypt(BlowfishContext *ctx,
+ u32 *in_blk, u32 *out_blk, int size);
+int blowfish_set_key(BlowfishContext *ctx,
+ unsigned char *key, int keybytes);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm: */\r
+/* */\r
+/* CAST-256 by Carlisle Adams of Entrust Tecnhologies */\r
+/* */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard */\r
+/* programme of the US National Institute of Standards and Technology. */\r
+/* */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions */\r
+/* that the originators of the algorithm place on its exploitation. */\r
+/* */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */\r
+\r
+/* Timing data for CAST-256 (cast.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 4333 cycles\r
+Encrypt: 633 cycles = 40.4 mbits/sec\r
+Decrypt: 634 cycles = 40.4 mbits/sec\r
+Mean: 634 cycles = 40.4 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 4342 cycles\r
+Encrypt: 633 cycles = 40.4 mbits/sec\r
+Decrypt: 633 cycles = 40.4 mbits/sec\r
+Mean: 633 cycles = 40.4 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 4325 cycles\r
+Encrypt: 639 cycles = 40.1 mbits/sec\r
+Decrypt: 638 cycles = 40.1 mbits/sec\r
+Mean: 639 cycles = 40.1 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 4294 cycles\r
+Encrypt: 678 cycles = 37.8 mbits/sec\r
+Decrypt: 669 cycles = 38.3 mbits/sec\r
+Mean: 674 cycles = 38.0 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 4314 cycles\r
+Encrypt: 678 cycles = 37.8 mbits/sec\r
+Decrypt: 670 cycles = 38.2 mbits/sec\r
+Mean: 674 cycles = 38.0 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 4313 cycles\r
+Encrypt: 678 cycles = 37.8 mbits/sec\r
+Decrypt: 669 cycles = 38.3 mbits/sec\r
+Mean: 674 cycles = 38.0 mbits/sec\r
+\r
+*/\r
+\r
+#include "silcincludes.h"\r
+#include "cast.h"\r
+ \r
+u4byte s_box[4][256] = \r
+{ {\r
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9C004dd3, \r
+ 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675,\r
+ 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059, \r
+ 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,\r
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, \r
+ 0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, \r
+ 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159, \r
+ 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,\r
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f,\r
+ 0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165,\r
+ 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0C50, 0x882240f2, 0x0c6e4f38, \r
+ 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,\r
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, \r
+ 0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, \r
+ 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb, \r
+ 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,\r
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, \r
+ 0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6,\r
+ 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6C2, 0x81383f05, 0x6963c5c8,\r
+ 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,\r
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, \r
+ 0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e,\r
+ 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426, \r
+ 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, \r
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, \r
+ 0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f,\r
+ 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, 0x7b5a41f0, 0xd37cfbad, \r
+ 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, \r
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, \r
+ 0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a,\r
+ 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, 0x3f04442f, 0x6188b153, \r
+ 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, \r
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, \r
+ 0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755,\r
+ 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, 0x580304f0, 0xca042cf1, \r
+ 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,\r
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, \r
+ 0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79,\r
+ 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814C, 0x474d6ad7, 0x7c0c5e5c, \r
+ 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,\r
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, \r
+ 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, \r
+ 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf\r
+ },\r
+ {\r
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a,\r
+ 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, \r
+ 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605, \r
+ 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,\r
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, \r
+ 0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, \r
+ 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083, \r
+ 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,\r
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, \r
+ 0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, \r
+ 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e, \r
+ 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,\r
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, \r
+ 0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, \r
+ 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064, \r
+ 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,\r
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, \r
+ 0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, \r
+ 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364, \r
+ 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,\r
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, \r
+ 0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, \r
+ 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c, \r
+ 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,\r
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, \r
+ 0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, \r
+ 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b, \r
+ 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,\r
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, \r
+ 0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, \r
+ 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028, \r
+ 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,\r
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6,\r
+ 0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, \r
+ 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1, \r
+ 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,\r
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, \r
+ 0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, \r
+ 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d, \r
+ 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,\r
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, \r
+ 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, \r
+ 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1\r
+ },\r
+ {\r
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b,\r
+ 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, \r
+ 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9,\r
+ 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,\r
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd,\r
+ 0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e,\r
+ 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264,\r
+ 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,\r
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, \r
+ 0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, \r
+ 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e, \r
+ 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,\r
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, \r
+ 0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, \r
+ 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e, \r
+ 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,\r
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, \r
+ 0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, \r
+ 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240, \r
+ 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,\r
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, \r
+ 0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15,\r
+ 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788, \r
+ 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,\r
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, \r
+ 0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, \r
+ 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f, \r
+ 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,\r
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, \r
+ 0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, \r
+ 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9, \r
+ 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,\r
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, \r
+ 0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, \r
+ 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2, \r
+ 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,\r
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, \r
+ 0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, \r
+ 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d, \r
+ 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,\r
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, \r
+ 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, \r
+ 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783\r
+ },\r
+ { \r
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, \r
+ 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, \r
+ 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd, \r
+ 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,\r
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, \r
+ 0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, \r
+ 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801, \r
+ 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,\r
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, \r
+ 0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746,\r
+ 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3, \r
+ 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,\r
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c,\r
+ 0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c,\r
+ 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16, \r
+ 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,\r
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7,\r
+ 0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, \r
+ 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002, \r
+ 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,\r
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, \r
+ 0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, \r
+ 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff, \r
+ 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,\r
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, \r
+ 0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, \r
+ 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec, \r
+ 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,\r
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, \r
+ 0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, \r
+ 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6,\r
+ 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,\r
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, \r
+ 0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, \r
+ 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6, \r
+ 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,\r
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2,\r
+ 0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, \r
+ 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda,\r
+ 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,\r
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6,\r
+ 0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e,\r
+ 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2\r
+ }\r
+};\r
+\r
+#define f1(y,x,kr,km) \\r
+ t = rotl(km + x, kr); \\r
+ u = s_box[0][byte(t,3)]; \\r
+ u ^= s_box[1][byte(t,2)]; \\r
+ u -= s_box[2][byte(t,1)]; \\r
+ u += s_box[3][byte(t,0)]; \\r
+ y ^= u\r
+\r
+#define f2(y,x,kr,km) \\r
+ t = rotl(km ^ x, kr); \\r
+ u = s_box[0][byte(t,3)]; \\r
+ u -= s_box[1][byte(t,2)]; \\r
+ u += s_box[2][byte(t,1)]; \\r
+ u ^= s_box[3][byte(t,0)]; \\r
+ y ^= u\r
+\r
+#define f3(y,x,kr,km) \\r
+ t = rotl(km - x, kr); \\r
+ u = s_box[0][byte(t,3)]; \\r
+ u += s_box[1][byte(t,2)]; \\r
+ u ^= s_box[2][byte(t,1)]; \\r
+ u -= s_box[3][byte(t,0)]; \\r
+ y ^= u\r
+\r
+#define f_rnd(x,n) \\r
+ f1(x[2],x[3],l_key[n], l_key[n + 4]); \\r
+ f2(x[1],x[2],l_key[n + 1],l_key[n + 5]); \\r
+ f3(x[0],x[1],l_key[n + 2],l_key[n + 6]); \\r
+ f1(x[3],x[0],l_key[n + 3],l_key[n + 7])\r
+\r
+#define i_rnd(x, n) \\r
+ f1(x[3],x[0],l_key[n + 3],l_key[n + 7]); \\r
+ f3(x[0],x[1],l_key[n + 2],l_key[n + 6]); \\r
+ f2(x[1],x[2],l_key[n + 1],l_key[n + 5]); \\r
+ f1(x[2],x[3],l_key[n], l_key[n + 4])\r
+\r
+#define k_rnd(k,tr,tm) \\r
+ f1(k[6],k[7],tr[0],tm[0]); \\r
+ f2(k[5],k[6],tr[1],tm[1]); \\r
+ f3(k[4],k[5],tr[2],tm[2]); \\r
+ f1(k[3],k[4],tr[3],tm[3]); \\r
+ f2(k[2],k[3],tr[4],tm[4]); \\r
+ f3(k[1],k[2],tr[5],tm[5]); \\r
+ f1(k[0],k[1],tr[6],tm[6]); \\r
+ f2(k[7],k[0],tr[7],tm[7])\r
+\r
+/* initialise the key schedule from the user supplied key */\r
+\r
+u4byte *cast_set_key(CastContext *ctx,\r
+ const u4byte in_key[], const u4byte key_len)\r
+{ \r
+ u4byte i, j, t, u, cm, cr, lk[8], tm[8], tr[8];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ for(i = 0; i < key_len / 32; ++i)\r
+\r
+ lk[i] = io_swap(in_key[i]);\r
+\r
+ for(; i < 8; ++i)\r
+\r
+ lk[i] = 0;\r
+\r
+ cm = 0x5a827999; cr = 19;\r
+\r
+ for(i = 0; i < 96; i += 8)\r
+ {\r
+ for(j = 0; j < 8; ++j)\r
+ {\r
+ tm[j] = cm; cm += 0x6ed9eba1;\r
+ tr[j] = cr; cr += 17;\r
+ }\r
+\r
+ k_rnd(lk, tr, tm);\r
+ \r
+ for(j = 0; j < 8; ++j)\r
+ {\r
+ tm[j] = cm; cm += 0x6ed9eba1;\r
+ tr[j] = cr; cr += 17;\r
+ }\r
+\r
+ k_rnd(lk, tr, tm);\r
+\r
+ l_key[i + 0] = lk[0]; l_key[i + 1] = lk[2];\r
+ l_key[i + 2] = lk[4]; l_key[i + 3] = lk[6];\r
+ l_key[i + 4] = lk[7]; l_key[i + 5] = lk[5];\r
+ l_key[i + 6] = lk[3]; l_key[i + 7] = lk[1];\r
+ }\r
+\r
+ return l_key;\r
+};\r
+\r
+/* encrypt a block of text */\r
+\r
+void cast_encrypt(CastContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[])\r
+{ \r
+ u4byte t, u, blk[4];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+ blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+ f_rnd(blk, 0); f_rnd(blk, 8);\r
+ f_rnd(blk, 16); f_rnd(blk, 24);\r
+ f_rnd(blk, 32); f_rnd(blk, 40);\r
+ i_rnd(blk, 48); i_rnd(blk, 56);\r
+ i_rnd(blk, 64); i_rnd(blk, 72);\r
+ i_rnd(blk, 80); i_rnd(blk, 88);\r
+\r
+ out_blk[0] = io_swap(blk[0]); out_blk[1] = io_swap(blk[1]);\r
+ out_blk[2] = io_swap(blk[2]); out_blk[3] = io_swap(blk[3]);\r
+};\r
+\r
+/* decrypt a block of text */\r
+\r
+void cast_decrypt(CastContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte t, u, blk[4];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+ blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+ f_rnd(blk, 88); f_rnd(blk, 80);\r
+ f_rnd(blk, 72); f_rnd(blk, 64);\r
+ f_rnd(blk, 56); f_rnd(blk, 48);\r
+ i_rnd(blk, 40); i_rnd(blk, 32);\r
+ i_rnd(blk, 24); i_rnd(blk, 16);\r
+ i_rnd(blk, 8); i_rnd(blk, 0);\r
+\r
+ out_blk[0] = io_swap(blk[0]); out_blk[1] = io_swap(blk[1]);\r
+ out_blk[2] = io_swap(blk[2]); out_blk[3] = io_swap(blk[3]);\r
+};\r
+\r
--- /dev/null
+/*
+
+ cast.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1999 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef CAST_H
+#define CAST_H
+
+#include "cast_internal.h"
+
+/*
+ * SILC Crypto API for Cast
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_cast_init(void *context,
+ const unsigned char *key,
+ unsigned int keylen)
+{
+ cast_set_key((CastContext *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+inline int silc_cast_set_string_as_key(void *context,
+ const unsigned char *string,
+ unsigned int stringlen)
+{
+ /* SilcHash hash;
+ unsigned char key[16];
+
+ silc_hash_alloc("md5", &hash);
+ hash->make_hash(hash, string, stringlen, key);
+
+ cast_set_key((CastContext *)context, (const u4byte *)key, sizeof(key));
+
+ silc_hash_free(hash);
+ memset(&key, 'F', sizeof(key));
+ */
+ return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+inline unsigned int silc_cast_context_len()
+{
+ return sizeof(CastContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_cast_encrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ unsigned int len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ cast_encrypt((CastContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ cast_encrypt((CastContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_cast_decrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ unsigned int len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ cast_decrypt((CastContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ cast_decrypt((CastContext *)context, in, out);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+
+ cast_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1999 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CAST_INTERNAL_H
+#define CAST_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+ u4byte l_key[96];
+} CastContext;
+
+/* Prototypes */
+u4byte *cast_set_key(CastContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void cast_encrypt(CastContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[]);
+void cast_decrypt(CastContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/*
+
+ ciphers.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CIPHERS_H
+#define CIPHERS_H
+
+#include "none.h"
+#include "mars.h"
+#include "rc6.h"
+#include "twofish.h"
+
+#endif
--- /dev/null
+/*
+
+ ciphers_def.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1999 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CIPHERS_DEF_H
+#define CIPHERS_DEF_H
+
+/* General definitions for algorithms */
+typedef unsigned char u1byte;
+typedef unsigned int u4byte;
+typedef unsigned int u32;
+
+#define rotr(x, nr) (((x) >> ((int)(nr))) | ((x) << (32 - (int)(nr))))
+#define rotl(x, nr) (((x) << ((int)(nr))) | ((x) >> (32 - (int)(nr))))
+#define byte(x, nr) ((x) >> (nr * 8) & 255)
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm: */\r
+/* */\r
+/* CRYPTON by Chae Hoon Lim of Future Systms Inc */\r
+/* */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard */\r
+/* programme of the US National Institute of Standards and Technology. */\r
+/* */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions */\r
+/* that the originators of the algorithm place on its exploitation. */\r
+/* */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */\r
+\r
+/* Timing data for CRYPTON (crypton.c)\r
+\r
+128 bit key:\r
+Key Setup: 531/1369 cycles (encrypt/decrypt)\r
+Encrypt: 474 cycles = 54.0 mbits/sec\r
+Decrypt: 474 cycles = 54.0 mbits/sec\r
+Mean: 474 cycles = 54.0 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 539/1381 cycles (encrypt/decrypt)\r
+Encrypt: 473 cycles = 54.1 mbits/sec\r
+Decrypt: 470 cycles = 54.5 mbits/sec\r
+Mean: 472 cycles = 54.3 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 552/1392 cycles (encrypt/decrypt)\r
+Encrypt: 469 cycles = 54.6 mbits/sec\r
+Decrypt: 483 cycles = 53.0 mbits/sec\r
+Mean: 476 cycles = 53.8 mbits/sec\r
+\r
+*/\r
+\r
+#include "silcincludes.h"\r
+#include "crypton.h"\r
+\r
+#define gamma_tau(x,b,m,p,q) \\r
+ (x) = (((u4byte)s_box[p][byte(b[0],m)] ) | \\r
+ ((u4byte)s_box[q][byte(b[1],m)] << 8) | \\r
+ ((u4byte)s_box[p][byte(b[2],m)] << 16) | \\r
+ ((u4byte)s_box[q][byte(b[3],m)] << 24))\r
+\r
+#define ma_0 0x3fcff3fc\r
+#define ma_1 0xfc3fcff3\r
+#define ma_2 0xf3fc3fcf\r
+#define ma_3 0xcff3fc3f\r
+\r
+#define mb_0 0xcffccffc\r
+#define mb_1 0xf33ff33f\r
+#define mb_2 0xfccffccf\r
+#define mb_3 0x3ff33ff3\r
+\r
+#define pi(b,n0,n1,n2,n3) \\r
+ (((b)[0] & ma_##n0) ^ \\r
+ ((b)[1] & ma_##n1) ^ \\r
+ ((b)[2] & ma_##n2) ^ \\r
+ ((b)[3] & ma_##n3))\r
+\r
+#define phi_n(x,n0,n1,n2,n3) \\r
+ ( (x) & mb_##n0) ^ \\r
+ (rotl((x), 8) & mb_##n1) ^ \\r
+ (rotl((x), 16) & mb_##n2) ^ \\r
+ (rotl((x), 24) & mb_##n3)\r
+\r
+#define phi_00(x) phi_n(x,0,1,2,3)\r
+#define phi_01(x) phi_n(x,3,0,1,2)\r
+#define phi_02(x) phi_n(x,2,3,0,1)\r
+#define phi_03(x) phi_n(x,1,2,3,0)\r
+\r
+#define phi_10(x) phi_n(x,3,0,1,2)\r
+#define phi_11(x) phi_n(x,2,3,0,1)\r
+#define phi_12(x) phi_n(x,1,2,3,0)\r
+#define phi_13(x) phi_n(x,0,1,2,3)\r
+\r
+#define phi0(x,y) \\r
+ (y)[0] = phi_00((x)[0]); \\r
+ (y)[1] = phi_01((x)[1]); \\r
+ (y)[2] = phi_02((x)[2]); \\r
+ (y)[3] = phi_03((x)[3])\r
+\r
+#define phi1(x,y) \\r
+ (y)[0] = phi_10((x)[0]); \\r
+ (y)[1] = phi_11((x)[1]); \\r
+ (y)[2] = phi_12((x)[2]); \\r
+ (y)[3] = phi_13((x)[3])\r
+\r
+u1byte p_box[3][16] = \r
+{ { 15, 9, 6, 8, 9, 9, 4, 12, 6, 2, 6, 10, 1, 3, 5, 15 },\r
+ { 10, 15, 4, 7, 5, 2, 14, 6, 9, 3, 12, 8, 13, 1, 11, 0 },\r
+ { 0, 4, 8, 4, 2, 15, 8, 13, 1, 1, 15, 7, 2, 11, 14, 15 }\r
+};\r
+\r
+u4byte tab_gen = 0;\r
+u1byte s_box[2][256];\r
+u4byte s_tab[4][256];\r
+\r
+void gen_tab(void)\r
+{ u4byte i, xl, xr, yl, yr;\r
+\r
+ for(i = 0; i < 256; ++i)\r
+ {\r
+ xl = (i & 0xf0) >> 4; xr = i & 15;\r
+\r
+ yr = xr ^ p_box[1][xl ^ p_box[0][xr]];\r
+ yl = xl ^ p_box[0][xr] ^ p_box[2][yr];\r
+\r
+ yr |= (yl << 4); s_box[0][i] = (u1byte)yr; s_box[1][yr] = (u1byte)i;\r
+\r
+ xr = yr * 0x01010101; xl = i * 0x01010101;\r
+\r
+ s_tab[0][ i] = xr & 0x3fcff3fc;\r
+ s_tab[1][yr] = xl & 0xfc3fcff3;\r
+ s_tab[2][ i] = xr & 0xf3fc3fcf;\r
+ s_tab[3][yr] = xl & 0xcff3fc3f;\r
+ }\r
+};\r
+\r
+/* initialise the key schedule from the user supplied key */\r
+\r
+u4byte kp[4] = { 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f };\r
+u4byte kq[4] = { 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 0xcbbb9d5d };\r
+\r
+#define h0_block(n,r0,r1) \\r
+ e_key[4 * n + 8] = rotl(e_key[4 * n + 0], r0); \\r
+ e_key[4 * n + 9] = rc ^ e_key[4 * n + 1]; \\r
+ e_key[4 * n + 10] = rotl(e_key[4 * n + 2], r1); \\r
+ e_key[4 * n + 11] = rc ^ e_key[4 * n + 3]\r
+\r
+#define h1_block(n,r0,r1) \\r
+ e_key[4 * n + 8] = rc ^ e_key[4 * n + 0]; \\r
+ e_key[4 * n + 9] = rotl(e_key[4 * n + 1], r0); \\r
+ e_key[4 * n + 10] = rc ^ e_key[4 * n + 2]; \\r
+ e_key[4 * n + 11] = rotl(e_key[4 * n + 3], r1)\r
+\r
+u4byte *crypton_set_key(CryptonContext *ctx,\r
+ const u4byte in_key[], const u4byte key_len)\r
+{ \r
+ u4byte i, rc, t0, t1, tmp[4];\r
+ u4byte *e_key = ctx->l_key + 52;\r
+ u4byte *d_key = ctx->l_key;\r
+\r
+ if(!tab_gen)\r
+ {\r
+ gen_tab(); tab_gen = 1;\r
+ }\r
+\r
+ e_key[2] = e_key[3] = e_key[6] = e_key[7] = 0;\r
+\r
+ switch((key_len + 63) / 64)\r
+ {\r
+ case 4: e_key[3] = in_key[6]; e_key[7] = in_key[7];\r
+ case 3: e_key[2] = in_key[4]; e_key[6] = in_key[5];\r
+ case 2: e_key[0] = in_key[0]; e_key[4] = in_key[1];\r
+ e_key[1] = in_key[2]; e_key[5] = in_key[3];\r
+ }\r
+\r
+ tmp[0] = pi(e_key, 0, 1, 2, 3) ^ kp[0];\r
+ tmp[1] = pi(e_key, 1, 2, 3, 0) ^ kp[1];\r
+ tmp[2] = pi(e_key, 2, 3, 0, 1) ^ kp[2];\r
+ tmp[3] = pi(e_key, 3, 0, 1, 2) ^ kp[3];\r
+ \r
+ gamma_tau(e_key[0], tmp, 0, 0, 1); \r
+ gamma_tau(e_key[1], tmp, 1, 1, 0);\r
+ gamma_tau(e_key[2], tmp, 2, 0, 1); \r
+ gamma_tau(e_key[3], tmp, 3, 1, 0);\r
+\r
+ tmp[0] = pi(e_key + 4, 1, 2, 3, 0) ^ kq[0]; \r
+ tmp[1] = pi(e_key + 4, 2, 3, 0, 1) ^ kq[1];\r
+ tmp[2] = pi(e_key + 4, 3, 0, 1, 2) ^ kq[2]; \r
+ tmp[3] = pi(e_key + 4, 0, 1, 2, 3) ^ kq[3];\r
+\r
+ gamma_tau(e_key[4], tmp, 0, 1, 0); \r
+ gamma_tau(e_key[5], tmp, 1, 0, 1);\r
+ gamma_tau(e_key[6], tmp, 2, 1, 0); \r
+ gamma_tau(e_key[7], tmp, 3, 0, 1);\r
+\r
+ t0 = e_key[0] ^ e_key[1] ^ e_key[2] ^ e_key[3];\r
+ t1 = e_key[4] ^ e_key[5] ^ e_key[6] ^ e_key[7];\r
+ \r
+ e_key[0] ^= t1; e_key[1] ^= t1;\r
+ e_key[2] ^= t1; e_key[3] ^= t1;\r
+ e_key[4] ^= t0; e_key[5] ^= t0;\r
+ e_key[6] ^= t0; e_key[7] ^= t0;\r
+\r
+ rc = 0x01010101; \r
+ h0_block( 0, 8, 16); h1_block(1, 16, 24); rc <<= 1;\r
+ h1_block( 2, 24, 8); h0_block(3, 8, 16); rc <<= 1;\r
+ h0_block( 4, 16, 24); h1_block(5, 24, 8); rc <<= 1;\r
+ h1_block( 6, 8, 16); h0_block(7, 16, 24); rc <<= 1;\r
+ h0_block( 8, 24, 8); h1_block(9, 8, 16); rc <<= 1;\r
+ h1_block(10, 16, 24);\r
+\r
+ for(i = 0; i < 13; ++i)\r
+ {\r
+ if(i & 1)\r
+ {\r
+ phi0(e_key + 4 * i, d_key + 48 - 4 * i);\r
+ }\r
+ else\r
+ {\r
+ phi1(e_key + 4 * i, d_key + 48 - 4 * i);\r
+ }\r
+ }\r
+\r
+ phi1(d_key + 48, d_key + 48);\r
+ phi1(e_key + 48, e_key + 48);\r
+\r
+ return l_key;\r
+};\r
+\r
+/* encrypt a block of text */\r
+\r
+#define fr0(i,k) \\r
+ b1[i] = s_tab[ (i) ][byte(b0[0],i)] ^ \\r
+ s_tab[((i) + 1) & 3][byte(b0[1],i)] ^ \\r
+ s_tab[((i) + 2) & 3][byte(b0[2],i)] ^ \\r
+ s_tab[((i) + 3) & 3][byte(b0[3],i)] ^ (k)\r
+\r
+#define fr1(i,k) \\r
+ b0[i] = s_tab[((i) + 1) & 3][byte(b1[0],i)] ^ \\r
+ s_tab[((i) + 2) & 3][byte(b1[1],i)] ^ \\r
+ s_tab[((i) + 3) & 3][byte(b1[2],i)] ^ \\r
+ s_tab[(i) ][byte(b1[3],i)] ^ (k)\r
+\r
+#define f0_rnd(kp) \\r
+ fr0(0,(kp)[0]); fr0(1,(kp)[1]); \\r
+ fr0(2,(kp)[2]); fr0(3,(kp)[3])\r
+\r
+#define f1_rnd(kp) \\r
+ fr1(0,(kp)[0]); fr1(1,(kp)[1]); \\r
+ fr1(2,(kp)[2]); fr1(3,(kp)[3])\r
+\r
+void crypton_encrypt(CryptonContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte b0[4], b1[4];\r
+ u4byte *e_key = ctx->l_key + 52;\r
+ u4byte *d_key = ctx->l_key;\r
+\r
+ b0[0] = in_blk[0] ^ e_key[0];\r
+ b0[1] = in_blk[1] ^ e_key[1];\r
+ b0[2] = in_blk[2] ^ e_key[2];\r
+ b0[3] = in_blk[3] ^ e_key[3];\r
+\r
+ f0_rnd(e_key + 4); f1_rnd(e_key + 8);\r
+ f0_rnd(e_key + 12); f1_rnd(e_key + 16);\r
+ f0_rnd(e_key + 20); f1_rnd(e_key + 24);\r
+ f0_rnd(e_key + 28); f1_rnd(e_key + 32);\r
+ f0_rnd(e_key + 36); f1_rnd(e_key + 40);\r
+ f0_rnd(e_key + 44);\r
+\r
+ gamma_tau(b0[0], b1, 0, 1, 0); \r
+ gamma_tau(b0[1], b1, 1, 0, 1); \r
+ gamma_tau(b0[2], b1, 2, 1, 0); \r
+ gamma_tau(b0[3], b1, 3, 0, 1);\r
+\r
+ out_blk[0] = b0[0] ^ e_key[48]; \r
+ out_blk[1] = b0[1] ^ e_key[49];\r
+ out_blk[2] = b0[2] ^ e_key[50]; \r
+ out_blk[3] = b0[3] ^ e_key[51];\r
+};\r
+\r
+/* decrypt a block of text */\r
+\r
+void crypton_decrypt(CryptonContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte b0[4], b1[4];\r
+ u4byte *e_key = ctx->l_key + 52;\r
+ u4byte *d_key = ctx->l_key;\r
+\r
+ b0[0] = in_blk[0] ^ d_key[0];\r
+ b0[1] = in_blk[1] ^ d_key[1];\r
+ b0[2] = in_blk[2] ^ d_key[2];\r
+ b0[3] = in_blk[3] ^ d_key[3];\r
+\r
+ f0_rnd(d_key + 4); f1_rnd(d_key + 8);\r
+ f0_rnd(d_key + 12); f1_rnd(d_key + 16);\r
+ f0_rnd(d_key + 20); f1_rnd(d_key + 24);\r
+ f0_rnd(d_key + 28); f1_rnd(d_key + 32);\r
+ f0_rnd(d_key + 36); f1_rnd(d_key + 40);\r
+ f0_rnd(d_key + 44);\r
+\r
+ gamma_tau(b0[0], b1, 0, 1, 0); \r
+ gamma_tau(b0[1], b1, 1, 0, 1); \r
+ gamma_tau(b0[2], b1, 2, 1, 0); \r
+ gamma_tau(b0[3], b1, 3, 0, 1);\r
+ \r
+ out_blk[0] = b0[0] ^ d_key[48]; \r
+ out_blk[1] = b0[1] ^ d_key[49];\r
+ out_blk[2] = b0[2] ^ d_key[50]; \r
+ out_blk[3] = b0[3] ^ d_key[51];\r
+};\r
--- /dev/null
+/*
+
+ crypton.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1999 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef CRYPTON_H
+#define CRYPTON_H
+
+#include "crypton_internal.h"
+
+/*
+ * SILC Crypto API for Crypton
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(crypton)
+{
+ crypton_set_key((CryptonContext *)context, (unsigned int *)key, keylen);
+ return TRUE;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(crypton)
+{
+ SilcHash hash;
+ unsigned char key[16];
+
+ silc_hash_alloc("md5", &hash);
+ hash->make_hash(hash, string, stringlen, key);
+
+ crypton_set_key((CryptonContext *)context, key, sizeof(key));
+
+ silc_hash_free(hash);
+ memset(&key, 'F', sizeof(key));
+
+ return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(crypton)
+{
+ return sizeof(CryptonContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(crypton)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ crypton_encrypt((CryptonContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ crypton_encrypt((CryptonContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_DECRYPT_CBC(crypton)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ crypton_decrypt((CryptonContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ crypton_decrypt((CryptonContext *)context, in, out);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return TRUE;
+}
+
+#endif
--- /dev/null
+/*
+
+ crypton_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1999 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef CRYPTON_INTERNAL_H
+#define CRYPTON_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+ u4byte l_key[104];
+} CryptonContext;
+
+/* Prototypes */
+u4byte *crypton_set_key(CryptonContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void crypton_encrypt(CryptonContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void crypton_decrypt(CryptonContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm: */\r
+/* */\r
+/* DFC designed by a team at CNRS and France Telecom */\r
+/* */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard */\r
+/* programme of the US National Institute of Standards and Technology. */\r
+/* */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions */\r
+/* that the originators of the algorithm place on its exploitation. */\r
+/* */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */\r
+/* */\r
+/* My thanks go to Serge Vaudenay of the Ecole Normale Superieure */\r
+/* for providing test vectors. This implementation has also been */\r
+/* tested with an independent implementation by Dr Russell Bradford */\r
+/* (Department of Mathematical Sciences, University of Bath, Bath, */\r
+/* UK) and checks out. My thanks go to Russell for his help in */\r
+/* comparing our implementations and finding bugs (and for help in */\r
+/* resolving 'endian' issues before test vectors became available). */\r
+\r
+/* Timing data for DFC (dfc.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+Algorithm: dfc (dfc.c)\r
+\r
+128 bit key:\r
+Key Setup: 5222 cycles\r
+Encrypt: 1203 cycles = 21.3 mbits/sec\r
+Decrypt: 1244 cycles = 20.6 mbits/sec\r
+Mean: 1224 cycles = 20.9 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 5203 cycles\r
+Encrypt: 1288 cycles = 19.9 mbits/sec\r
+Decrypt: 1235 cycles = 20.7 mbits/sec\r
+Mean: 1262 cycles = 20.3 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 5177 cycles\r
+Encrypt: 1178 cycles = 21.7 mbits/sec\r
+Decrypt: 1226 cycles = 20.9 mbits/sec\r
+Mean: 1202 cycles = 21.3 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 5227 cycles\r
+Encrypt: 1247 cycles = 20.5 mbits/sec\r
+Decrypt: 1222 cycles = 20.9 mbits/sec\r
+Mean: 1235 cycles = 20.7 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 5252 cycles\r
+Encrypt: 1215 cycles = 21.1 mbits/sec\r
+Decrypt: 1265 cycles = 20.2 mbits/sec\r
+Mean: 1240 cycles = 20.6 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 5174 cycles\r
+Encrypt: 1247 cycles = 20.5 mbits/sec\r
+Decrypt: 1206 cycles = 21.2 mbits/sec\r
+Mean: 1227 cycles = 20.9 mbits/sec\r
+\r
+*/\r
+\r
+/* The EES string is as follows (the abstract contains an error in \r
+ the last line of this sequence which changes KC and KD):\r
+\r
+ 0xb7e15162, 0x8aed2a6a, 0xbf715880, 0x9cf4f3c7, \r
+ 0x62e7160f, 0x38b4da56, 0xa784d904, 0x5190cfef, \r
+ 0x324e7738, 0x926cfbe5, 0xf4bf8d8d, 0x8c31d763,\r
+ 0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
+\r
+ 0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce, \r
+ 0xd55c4d79, 0xfd5f24d6, 0x613c31c3, 0x839a2ddf,\r
+ 0x8a9a276b, 0xcfbfa1c8, 0x77c56284, 0xdab79cd4, \r
+ 0xc2b3293d, 0x20e9e5ea, 0xf02ac60a, 0xcc93ed87, \r
+\r
+ 0x4422a52e, 0xcb238fee, 0xe5ab6add, 0x835fd1a0,\r
+ 0x753d0a8f, 0x78e537d2, 0xb95bb79d, 0x8dcaec64, \r
+ 0x2c1e9f23, 0xb829b5c2, 0x780bf387, 0x37df8bb3, \r
+ 0x00d01334, 0xa0d0bd86, 0x45cbfa73, 0xa6160ffe,\r
+\r
+ 0x393c48cb, 0xbbca060f, 0x0ff8ec6d, 0x31beb5cc, \r
+ 0xeed7f2f0, 0xbb088017, 0x163bc60d, 0xf45a0ecb, \r
+ 0x1bcd289b, 0x06cbbfea, 0x21ad08e1, 0x847f3f73,\r
+ 0x78d56ced, 0x94640d6e, 0xf0d3d37b, 0xe67008e1, \r
+ \r
+ 0x86d1bf27, 0x5b9b241d, 0xeb64749a, 0x47dfdfb9, \r
+\r
+ Where:\r
+\r
+ EES = RT(0) | RT(1) | ... | RT(63) | KD | KC\r
+\r
+ Note that the abstract describing DFC is written \r
+ in big endian notation with the most significant \r
+ digits of a sequence of digits placed at the low\r
+ index positions in arrays. This format is used\r
+ here and is only converted to machine format at\r
+ the point that maths is done on any numbers in \r
+ the round function.\r
+ \r
+ The key input is thus treated as an array of 32 \r
+ bit words numbered from 0..3, 0..5 or 0..7 \r
+ depending on key length. The first (leftmost) \r
+ bit of this key string as defined in the DFC \r
+ abstract is the most significant bit of word 0 \r
+ and the rightmost bit of this string is the least \r
+ signicant bit of the highest numbered key word.\r
+\r
+ The input and output blocks for the cipher are \r
+ also treated as arrays of 32 bit words numbered\r
+ from 0..3. The most significant bit of word 0 is\r
+ the 1st (leftmost) bit of the 128 bit input string \r
+ and the least significant bit of word 3 is the \r
+ last (rightmost) bit.\r
+ \r
+ Note that the inputs, the output and the key are\r
+ in Intel little endian format when BYTE_SWAP is \r
+ defined\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "dfc_internal.h"\r
+\r
+/* The following arrays are all stored in big endian */\r
+/* format with 32 bit words at lower array positions */\r
+/* being more significant in multi-word values */\r
+\r
+u4byte rt64[64] = \r
+{\r
+ 0xb7e15162, 0x8aed2a6a, 0xbf715880, 0x9cf4f3c7, \r
+ 0x62e7160f, 0x38b4da56, 0xa784d904, 0x5190cfef, \r
+ 0x324e7738, 0x926cfbe5, 0xf4bf8d8d, 0x8c31d763,\r
+ 0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
+\r
+ 0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce, \r
+ 0xd55c4d79, 0xfd5f24d6, 0x613c31c3, 0x839a2ddf,\r
+ 0x8a9a276b, 0xcfbfa1c8, 0x77c56284, 0xdab79cd4, \r
+ 0xc2b3293d, 0x20e9e5ea, 0xf02ac60a, 0xcc93ed87, \r
+\r
+ 0x4422a52e, 0xcb238fee, 0xe5ab6add, 0x835fd1a0,\r
+ 0x753d0a8f, 0x78e537d2, 0xb95bb79d, 0x8dcaec64, \r
+ 0x2c1e9f23, 0xb829b5c2, 0x780bf387, 0x37df8bb3, \r
+ 0x00d01334, 0xa0d0bd86, 0x45cbfa73, 0xa6160ffe,\r
+\r
+ 0x393c48cb, 0xbbca060f, 0x0ff8ec6d, 0x31beb5cc, \r
+ 0xeed7f2f0, 0xbb088017, 0x163bc60d, 0xf45a0ecb, \r
+ 0x1bcd289b, 0x06cbbfea, 0x21ad08e1, 0x847f3f73,\r
+ 0x78d56ced, 0x94640d6e, 0xf0d3d37b, 0xe67008e1, \r
+};\r
+\r
+u4byte kc = 0xeb64749a;\r
+\r
+u4byte kd2[2] = \r
+{\r
+ 0x86d1bf27, 0x5b9b241d \r
+};\r
+\r
+u4byte ka2[6] = \r
+{\r
+ 0xb7e15162, 0x8aed2a6a, \r
+ 0xbf715880, 0x9cf4f3c7, \r
+ 0x62e7160f, 0x38b4da56, \r
+};\r
+\r
+u4byte kb2[6] =\r
+{\r
+ 0xa784d904, 0x5190cfef, \r
+ 0x324e7738, 0x926cfbe5, \r
+ 0xf4bf8d8d, 0x8c31d763,\r
+};\r
+\r
+u4byte ks8[8] = \r
+{ 0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
+ 0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce,\r
+};\r
+\r
+#define lo(x) ((x) & 0x0000ffff)\r
+#define hi(x) ((x) >> 16)\r
+\r
+#define mult_64(r,x,y) \\r
+ x0 = lo(x[1]); x1 = hi(x[1]); x2 = lo(x[0]); x3 = hi(x[0]); \\r
+ y0 = lo(y[1]); y1 = hi(y[1]); y2 = lo(y[0]); y3 = hi(y[0]); \\r
+ t0 = x0 * y0; r[0] = lo(t0); c = hi(t0); \\r
+ t0 = x0 * y1; t1 = x1 * y0; c += lo(t0) + lo(t1); \\r
+ r[0] += (c << 16); c = hi(c) + hi(t0) + hi(t1); \\r
+ t0 = x0 * y2; t1 = x1 * y1; t2 = x2 * y0; \\r
+ c += lo(t0) + lo(t1) + lo(t2); r[1] = lo(c); \\r
+ c = hi(c) + hi(t0) + hi(t1) + hi(t2); \\r
+ t0 = x0 * y3; t1 = x1 * y2; t2 = x2 * y1; t3 = x3 * y0; \\r
+ c += lo(t0) + lo(t1) + lo(t2) + lo(t3); r[1] += (c << 16); \\r
+ c = hi(c) + hi(t0) + hi(t1) + hi(t2) + hi(t3); \\r
+ t0 = x1 * y3; t1 = x2 * y2; t2 = x3 * y1; \\r
+ c += lo(t0) + lo(t1) + lo(t2); r[2] = lo(c); \\r
+ c = hi(c) + hi(t0) + hi(t1) + hi(t2); \\r
+ t0 = x2 * y3; t1 = x3 * y2; c += lo(t0) + lo(t1); \\r
+ r[2] += (c << 16); c = hi(c) + hi(t0) + hi(t1); \\r
+ r[3] = c + x3 * y3\r
+\r
+#define add_64(r,hi,lo) \\r
+ if((r[0] += lo) < lo) \\r
+ if(!++r[1]) \\r
+ if(!++r[2]) \\r
+ ++r[3]; \\r
+ if((r[1] += hi) < hi) \\r
+ if(!++r[2]) \\r
+ ++r[3]\r
+ \r
+#define mult_13(r) \\r
+ c = 13 * lo((r)[0]); \\r
+ d = hi((r)[0]); \\r
+ (r)[0] = lo(c); \\r
+ c = hi(c) + 13 * d; \\r
+ (r)[0] += (c << 16); \\r
+ c = hi(c) + 13 * lo((r)[1]); \\r
+ d = hi((r)[1]); \\r
+ (r)[1] = lo(c); \\r
+ c = hi(c) + 13 * d; \\r
+ (r)[1] += (c << 16); \\r
+ (r)[2] = hi(c)\r
+\r
+/* Where necessary this is where conversion from big endian to */\r
+/* little endian format is performed. Since all the maths is */\r
+/* little endian care is needed when 64 bit blocks are being */\r
+/* used to get them in the right order by reversing the order */\r
+/* in which these are stored. This applies to the key array */\r
+/* which gives the two values A and B and to the constant KD. */\r
+/* Since the input and output blocks are big endian we also */\r
+/* have to invert the order of the 32 bit words in the 64 bit */\r
+/* blocks being processed. */ \r
+\r
+void r_fun(u4byte outp[2], const u4byte inp[2], const u4byte key[4])\r
+{ u4byte acc[5], x0, x1, x2, x3, y0, y1, y2, y3, t0, t1, t2, t3, c, d;\r
+\r
+ mult_64(acc, inp, key); add_64(acc, key[2], key[3]);\r
+\r
+ /* we need the value in the accumulator mod 2^64 + 13 so if */\r
+ /* the accumulator value is hi * 2^64 + lo we need to find */\r
+ /* a k value such that r = hi * 2^64 + lo - k * (2^64 + 13) */\r
+ /* is 0 <= r < 2^64 + 13. We can see that k will be close */\r
+ /* to hi in value - it may equal hi but will not be greater */\r
+ /* and we can let k = hi - e with e >= 0 so that r is given */\r
+ /* by r = e * (2^64 + 13) + lo - 13 * hi. If we compute the */\r
+ /* lo - 13 * hi value, the overflow into the top 64 bits of */\r
+ /* the accumulator has to be 'zeroed' by the e * (2^64 + 13)*/\r
+ /* term and this sets the e value (in fact such an overlow */\r
+ /* is only removed when the lower word is higher than 12). */\r
+\r
+ mult_13(acc + 2); /* multiply top of accumulator by 13 */\r
+\r
+ /* calculate lo - 13 * hi in acc[0] and acc[1] with any */\r
+ /* overflow into top 64 bits in c */\r
+\r
+ d = acc[0]; acc[0] -= acc[2]; c = (acc[0] > d ? 1 : 0);\r
+\r
+ d = acc[1]; acc[1] -= acc[3] + c;\r
+ c = (acc[1] > d ? 1 : (acc[1] == d ? c : 0));\r
+\r
+ c = 13 * (acc[4] + c); /* overflow into top 64 bits of acc */\r
+\r
+ if(((acc[0] += c) < c) && !(++acc[1]))\r
+ {\r
+ if(acc[0] > 12)\r
+\r
+ acc[0] -= 13;\r
+ }\r
+\r
+ /* do the confusion permutation */\r
+\r
+ d = acc[1] ^ kc; c = acc[0] ^ rt64[acc[1] >> 26]; \r
+ \r
+ c += kd2[0] + ((d += kd2[1]) < kd2[1] ? 1 : 0);\r
+\r
+ outp[0] ^= c; outp[1] ^= d; \r
+};\r
+\r
+u4byte *dfc_set_key(DfcContext *ctx,\r
+ const u4byte in_key[], const u4byte key_len)\r
+{ \r
+ u4byte i, lk[32], rk[4];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ for(i = 0; i < key_len / 32; ++i)\r
+\r
+ lk[i] = io_swap(in_key[i]);\r
+\r
+ /* pad the key with the KS array */\r
+\r
+ for(i = 0; i < 8 - key_len / 32; ++i) /* K|KS */\r
+\r
+ lk[i + key_len / 32] = ks8[i];\r
+\r
+ /* do the reordering of the key parameters */\r
+ /* the OAP[1]|OBP[1]|OAP[2]... sequence is */\r
+ /* at lk[0]... and the other at lk[16]... */\r
+ \r
+ lk[18] = lk[5]; lk[19] = lk[2]; /* EBP */ \r
+ lk[16] = lk[1]; lk[17] = lk[6]; /* EAP */\r
+ lk[ 2] = lk[4]; lk[ 3] = lk[3]; /* OBP */\r
+ lk[ 0] = lk[0]; lk[ 1] = lk[7]; /* OAP */\r
+\r
+ /* create other elements using KA and KB */\r
+\r
+ for(i = 0; i < 6; i += 2)\r
+ {\r
+ lk[i + i + 4] = lk[ 0] ^ ka2[i]; /* OAP[i] ms */\r
+ lk[i + i + 5] = lk[ 1] ^ ka2[i + 1]; /* OAP[i] ls */\r
+ lk[i + i + 6] = lk[ 2] ^ kb2[i]; /* OBP[i] ms */\r
+ lk[i + i + 7] = lk[ 3] ^ kb2[i + 1]; /* OBP[i] ls */\r
+ lk[i + i + 20] = lk[16] ^ ka2[i]; /* EAP[i] ms */\r
+ lk[i + i + 21] = lk[17] ^ ka2[i + 1]; /* EAP[i] ls */\r
+ lk[i + i + 22] = lk[18] ^ kb2[i]; /* EBP[i] ms */\r
+ lk[i + i + 23] = lk[19] ^ kb2[i + 1]; /* EBP[i] ls */\r
+ }\r
+\r
+ rk[0] = rk[1] = rk[2] = rk[3] = 0;\r
+\r
+ /* do the 4 round key mixing encryption */\r
+\r
+ for(i = 0; i < 32; i += 8)\r
+ {\r
+ r_fun(rk, rk + 2, lk); /* R2|R1 */\r
+ r_fun(rk + 2, rk, lk + 4); /* R2|R3 */\r
+ r_fun(rk, rk + 2, lk + 8); /* R4|R3 */\r
+ r_fun(rk + 2, rk, lk + 12); /* R4|R5 */\r
+\r
+ /* keep key in big endian format with */\r
+ /* the most significant 32 bit words */\r
+ /* first (lowest) in the key schedule */\r
+ /* - note that the upper and lower 64 */\r
+ /* bit blocks are in inverse order at */\r
+ /* this point in the loop */\r
+\r
+ l_key[i + 0] = rk[2]; l_key[i + 1] = rk[3]; \r
+ l_key[i + 2] = rk[0]; l_key[i + 3] = rk[1]; \r
+\r
+ r_fun(rk + 2, rk, lk + 16); /* R1|R2 */\r
+ r_fun(rk, rk + 2, lk + 20); /* R3|R2 */\r
+ r_fun(rk + 2, rk, lk + 24); /* R3|R4 */ \r
+ r_fun(rk, rk + 2, lk + 28); /* R5|R4 */\r
+\r
+ l_key[i + 4] = rk[0]; l_key[i + 5] = rk[1]; \r
+ l_key[i + 6] = rk[2]; l_key[i + 7] = rk[3];\r
+ }\r
+ \r
+ return l_key;\r
+};\r
+\r
+void dfc_encrypt(DfcContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte blk[4];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ /* the input/output format is big endian - */\r
+ /* any reversals needed are performed when */\r
+ /* maths is done in the round function */\r
+\r
+ blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+ blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+ r_fun(blk, blk + 2, l_key + 0); /* R2|R1 */ \r
+ r_fun(blk + 2, blk, l_key + 4); /* R2|R3 */\r
+ r_fun(blk, blk + 2, l_key + 8); /* R4|R3 */\r
+ r_fun(blk + 2, blk, l_key + 12); /* R4|R5 */\r
+ r_fun(blk, blk + 2, l_key + 16); /* R6|R5 */\r
+ r_fun(blk + 2, blk, l_key + 20); /* R6|R7 */\r
+ r_fun(blk, blk + 2, l_key + 24); /* R8|R7 */\r
+ r_fun(blk + 2, blk, l_key + 28); /* R8|R9 */\r
+\r
+ /* swap order to obtain the result R9|R8 */\r
+\r
+ out_blk[0] = io_swap(blk[2]); out_blk[1] = io_swap(blk[3]);\r
+ out_blk[2] = io_swap(blk[0]); out_blk[3] = io_swap(blk[1]);\r
+};\r
+\r
+void dfc_decrypt(DfcContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte blk[4];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ /* the input/output format is big endian - */\r
+ /* any reversals needed are performed when */\r
+ /* maths is done in the round function */\r
+\r
+ blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+ blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+ r_fun(blk, blk + 2, l_key + 28); /* R7|R8 */\r
+ r_fun(blk + 2, blk, l_key + 24); /* R7|R6 */\r
+ r_fun(blk, blk + 2, l_key + 20); /* R5|R6 */\r
+ r_fun(blk + 2, blk, l_key + 16); /* R5|R4 */\r
+ r_fun(blk, blk + 2, l_key + 12); /* R3|R4 */\r
+ r_fun(blk + 2, blk, l_key + 8); /* R3|R2 */\r
+ r_fun(blk, blk + 2, l_key + 4); /* R1|R2 */\r
+ r_fun(blk + 2, blk, l_key ); /* R1|R0 */ \r
+\r
+ /* swap order to obtain the result R1|R0 */\r
+\r
+ out_blk[0] = io_swap(blk[2]); out_blk[1] = io_swap(blk[3]);\r
+ out_blk[2] = io_swap(blk[0]); out_blk[3] = io_swap(blk[1]); \r
+};\r
--- /dev/null
+/*
+
+ dfc.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef DFC_H
+#define DFC_H
+
+#include "dfc_internal.h"
+
+/*
+ * SILC Crypto API for DFC
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_dfc_init(void *context,
+ const unsigned char *key,
+ unsigned int keylen)
+{
+ dfc_set_key((DfcContext *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+inline int silc_dfc_set_string_as_key(void *context,
+ const unsigned char *string,
+ unsigned int keylen)
+{
+ /* SilcHash hash;
+ unsigned char key[16];
+
+ silc_hash_alloc("md5", &hash);
+ hash->make_hash(hash, string, stringlen, key);
+
+ dfc_set_key((DfcContext *)context, key, sizeof(key));
+
+ silc_hash_free(hash);
+ memset(&key, 'F', sizeof(key));
+ */
+ return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+inline unsigned int silc_dfc_context_len()
+{
+ return sizeof(DfcContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_dfc_encrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ unsigned int len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ dfc_encrypt((DfcContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ dfc_encrypt((DfcContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_dfc_decrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ unsigned int len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ dfc_decrypt((DfcContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ dfc_decrypt((DfcContext *)context, in, out);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+
+ dfc_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef DFC_INTERNAL_H
+#define DFC_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+ u4byte l_key[32];
+} DfcContext;
+
+/* Prototypes */
+u4byte *dfc_set_key(DfcContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void dfc_encrypt(DfcContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void dfc_decrypt(DfcContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm: */\r
+/* */\r
+/* E2 by Nippon Telegraph and Telephone (NTT) Japan */\r
+/* */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard */\r
+/* programme of the US National Institute of Standards and Technology. */\r
+/* */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions */\r
+/* that the originators of the algorithm place on its exploitation. */\r
+/* */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */\r
+/* */\r
+/* In accordance with the wishes of NTT this implementation is made */\r
+/* available for academic and study purposes only. I gratefully */\r
+/* acknowledge the contributions made by Kazumaro Aoki of NTT Japan */\r
+/* for ways to increase the speed of this implementation. */\r
+\r
+/* Timing data for E2 (e28.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 9473 cycles\r
+Encrypt: 687 cycles = 37.3 mbits/sec\r
+Decrypt: 691 cycles = 37.0 mbits/sec\r
+Mean: 689 cycles = 37.2 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 9540 cycles\r
+Encrypt: 696 cycles = 36.8 mbits/sec\r
+Decrypt: 693 cycles = 36.9 mbits/sec\r
+Mean: 695 cycles = 36.9 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 9913 cycles\r
+Encrypt: 691 cycles = 37.0 mbits/sec\r
+Decrypt: 706 cycles = 36.3 mbits/sec\r
+Mean: 699 cycles = 36.6 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 9598 cycles\r
+Encrypt: 730 cycles = 35.1 mbits/sec\r
+Decrypt: 723 cycles = 35.4 mbits/sec\r
+Mean: 727 cycles = 35.2 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 9393 cycles\r
+Encrypt: 730 cycles = 35.1 mbits/sec\r
+Decrypt: 720 cycles = 35.6 mbits/sec\r
+Mean: 725 cycles = 35.3 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 9720 cycles\r
+Encrypt: 727 cycles = 35.2 mbits/sec\r
+Decrypt: 721 cycles = 35.5 mbits/sec\r
+Mean: 724 cycles = 35.4 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "e2_internal.h"\r
+\r
+u1byte s_box[] =\r
+{\r
+ 0xe1, 0x42, 0x3e, 0x81, 0x4e, 0x17, 0x9e, 0xfd, 0xb4, 0x3f, 0x2c, 0xda,\r
+ 0x31, 0x1e, 0xe0, 0x41, 0xcc, 0xf3, 0x82, 0x7d, 0x7c, 0x12, 0x8e, 0xbb,\r
+ 0xe4, 0x58, 0x15, 0xd5, 0x6f, 0xe9, 0x4c, 0x4b, 0x35, 0x7b, 0x5a, 0x9a,\r
+ 0x90, 0x45, 0xbc, 0xf8, 0x79, 0xd6, 0x1b, 0x88, 0x02, 0xab, 0xcf, 0x64,\r
+ 0x09, 0x0c, 0xf0, 0x01, 0xa4, 0xb0, 0xf6, 0x93, 0x43, 0x63, 0x86, 0xdc,\r
+ 0x11, 0xa5, 0x83, 0x8b, 0xc9, 0xd0, 0x19, 0x95, 0x6a, 0xa1, 0x5c, 0x24,\r
+ 0x6e, 0x50, 0x21, 0x80, 0x2f, 0xe7, 0x53, 0x0f, 0x91, 0x22, 0x04, 0xed,\r
+ 0xa6, 0x48, 0x49, 0x67, 0xec, 0xf7, 0xc0, 0x39, 0xce, 0xf2, 0x2d, 0xbe,\r
+ 0x5d, 0x1c, 0xe3, 0x87, 0x07, 0x0d, 0x7a, 0xf4, 0xfb, 0x32, 0xf5, 0x8c,\r
+ 0xdb, 0x8f, 0x25, 0x96, 0xa8, 0xea, 0xcd, 0x33, 0x65, 0x54, 0x06, 0x8d,\r
+ 0x89, 0x0a, 0x5e, 0xd9, 0x16, 0x0e, 0x71, 0x6c, 0x0b, 0xff, 0x60, 0xd2,\r
+ 0x2e, 0xd3, 0xc8, 0x55, 0xc2, 0x23, 0xb7, 0x74, 0xe2, 0x9b, 0xdf, 0x77,\r
+ 0x2b, 0xb9, 0x3c, 0x62, 0x13, 0xe5, 0x94, 0x34, 0xb1, 0x27, 0x84, 0x9f,\r
+ 0xd7, 0x51, 0x00, 0x61, 0xad, 0x85, 0x73, 0x03, 0x08, 0x40, 0xef, 0x68,\r
+ 0xfe, 0x97, 0x1f, 0xde, 0xaf, 0x66, 0xe8, 0xb8, 0xae, 0xbd, 0xb3, 0xeb,\r
+ 0xc6, 0x6b, 0x47, 0xa9, 0xd8, 0xa7, 0x72, 0xee, 0x1d, 0x7e, 0xaa, 0xb6,\r
+ 0x75, 0xcb, 0xd4, 0x30, 0x69, 0x20, 0x7f, 0x37, 0x5b, 0x9d, 0x78, 0xa3,\r
+ 0xf1, 0x76, 0xfa, 0x05, 0x3d, 0x3a, 0x44, 0x57, 0x3b, 0xca, 0xc7, 0x8a,\r
+ 0x18, 0x46, 0x9c, 0xbf, 0xba, 0x38, 0x56, 0x1a, 0x92, 0x4d, 0x26, 0x29,\r
+ 0xa2, 0x98, 0x10, 0x99, 0x70, 0xa0, 0xc5, 0x28, 0xc1, 0x6d, 0x14, 0xac,\r
+ 0xf9, 0x5f, 0x4f, 0xc4, 0xc3, 0xd1, 0xfc, 0xdd, 0xb2, 0x59, 0xe6, 0xb5,\r
+ 0x36, 0x52, 0x4a, 0x2a\r
+};\r
+\r
+u4byte l_box[4][256];\r
+u4byte lb_init = 0;\r
+\r
+#define v_0 0x67452301\r
+#define v_1 0xefcdab89\r
+\r
+/* s_fun(s_fun(s_fun(v))) */\r
+\r
+#define k2_0 0x30d32e58\r
+#define k2_1 0xb89e4984\r
+\r
+/* s_fun(s_fun(s_fun(s_fun(v)))) */\r
+\r
+#define k3_0 0x0957cfec\r
+#define k3_1 0xd800502e\r
+\r
+#define bp_fun(a,b,c,d,e,f,g,h) \\r
+ u = (e ^ g) & 0x00ffff00; \\r
+ v = (f ^ h) & 0x0000ffff; \\r
+ a = e ^ u; c = g ^ u; \\r
+ b = f ^ v; d = h ^ v\r
+\r
+#define ibp_fun(a,b,c,d,e,f,g,h) \\r
+ u = (e ^ g) & 0xff0000ff; \\r
+ v = (f ^ h) & 0xffff0000; \\r
+ a = e ^ u; c = g ^ u; \\r
+ b = f ^ v; d = h ^ v\r
+\r
+#define bp2_fun(x,y) \\r
+ w = (x ^ y) & 0x00ff00ff; \\r
+ x ^= w; y ^= w; \\r
+\r
+#define s_fun(x,y) \\r
+ p = x; q = x >> 8; \\r
+ r = y; s = y >> 8; \\r
+ x = l_box[0][r & 255]; \\r
+ y = l_box[0][p & 255]; \\r
+ p >>= 16; r >>= 16; \\r
+ x |= l_box[1][q & 255]; \\r
+ y |= l_box[1][s & 255]; \\r
+ x |= l_box[2][r & 255]; \\r
+ y |= l_box[2][p & 255]; \\r
+ x |= l_box[3][p >> 8]; \\r
+ y |= l_box[3][r >> 8]\r
+\r
+#define sx_fun(x,y) \\r
+ p = x >> 8; \\r
+ q = x >> 16; \\r
+ x = l_box[0][x & 255]; \\r
+ x |= l_box[1][p & 255]; \\r
+ x |= l_box[2][q & 255]; \\r
+ x |= l_box[3][q >> 8]; \\r
+ p = y >> 8; \\r
+ q = y >> 16; \\r
+ y = l_box[0][y & 255]; \\r
+ y |= l_box[1][p & 255]; \\r
+ y |= l_box[2][q & 255]; \\r
+ y |= l_box[3][q >> 8]\r
+\r
+#define spx_fun(x,y) \\r
+ sx_fun(x,y); \\r
+ y ^= x; \\r
+ x ^= rotr(y, 16); \\r
+ y ^= rotr(x, 8); \\r
+ x ^= y\r
+\r
+#define sp_fun(x,y) \\r
+ s_fun(x,y); \\r
+ y ^= x; \\r
+ x ^= rotr(y, 16); \\r
+ y ^= rotr(x, 8); \\r
+ x ^= y\r
+\r
+#define sr_fun(x,y) \\r
+ p = x; q = x >> 8; \\r
+ r = y; s = y >> 8; \\r
+ y = l_box[1][p & 255]; \\r
+ x = l_box[1][r & 255]; \\r
+ p >>= 16; r >>= 16; \\r
+ x |= l_box[2][q & 255]; \\r
+ y |= l_box[2][s & 255]; \\r
+ y |= l_box[3][p & 255]; \\r
+ x |= l_box[3][r & 255]; \\r
+ x |= l_box[0][r >> 8]; \\r
+ y |= l_box[0][p >> 8]\r
+\r
+#define f_fun(a,b,c,d,k) \\r
+ u = c ^ *(k); v = d ^ *(k + 1); \\r
+ sp_fun(u, v); \\r
+ u ^= *(k + 2); v ^= *(k + 3); \\r
+ sr_fun(u, v); \\r
+ a ^= v; \\r
+ b ^= u\r
+\r
+#define byte_adr(x,n) *(((u1byte*)&x)+n)\r
+\r
+u4byte mod_inv(u4byte x)\r
+{ u4byte y1, y2, a, b, q;\r
+\r
+ y1 = ~((-x) / x); y2 = 1;\r
+\r
+ a = x; b = y1 * x;\r
+\r
+ for(;;)\r
+ {\r
+ q = a / b; \r
+ \r
+ if((a -= q * b) == 0)\r
+\r
+ return (x * y1 == 1 ? y1 : -y1);\r
+ \r
+ y2 -= q * y1;\r
+\r
+ q = b / a; \r
+ \r
+ if((b -= q * a) == 0)\r
+ \r
+ return (x * y2 == 1 ? y2 : -y2);\r
+\r
+ y1 -= q * y2;\r
+ }\r
+};\r
+\r
+void g_fun(u4byte y[8], u4byte l[8], u4byte v[2])\r
+{ u4byte p,q;\r
+\r
+ spx_fun(y[0], y[1]); spx_fun(v[0], v[1]); \r
+ l[0] = v[0] ^= y[0]; l[1] = v[1] ^= y[1];\r
+\r
+ spx_fun(y[2], y[3]); spx_fun(v[0], v[1]); \r
+ l[2] = v[0] ^= y[2]; l[3] = v[1] ^= y[3];\r
+\r
+ spx_fun(y[4], y[5]); spx_fun(v[0], v[1]); \r
+ l[4] = v[0] ^= y[4]; l[5] = v[1] ^= y[5];\r
+\r
+ spx_fun(y[6], y[7]); spx_fun(v[0], v[1]); \r
+ l[6] = v[0] ^= y[6]; l[7] = v[1] ^= y[7];\r
+};\r
+\r
+u4byte *e2_set_key(E2Context *ctx,\r
+ const u4byte in_key[], const u4byte key_len)\r
+{ \r
+ u4byte lk[8], v[2], lout[8];\r
+ u4byte i, j, k, w;\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ if(!lb_init)\r
+ {\r
+ for(i = 0; i < 256; ++i)\r
+ {\r
+ l_box[0][i] = ((u4byte)(s_box[i]));\r
+ l_box[1][i] = ((u4byte)(s_box[i])) << 8;\r
+ l_box[2][i] = ((u4byte)(s_box[i])) << 16;\r
+ l_box[3][i] = ((u4byte)(s_box[i])) << 24;\r
+ }\r
+\r
+ lb_init = 1;\r
+ }\r
+\r
+ v[0] = bswap(v_0); v[1] = bswap(v_1);\r
+\r
+ lk[0] = io_swap(in_key[0]); lk[1] = io_swap(in_key[1]);\r
+ lk[2] = io_swap(in_key[2]); lk[3] = io_swap(in_key[3]);\r
+\r
+ lk[4] = io_swap(key_len > 128 ? in_key[4] : k2_0);\r
+ lk[5] = io_swap(key_len > 128 ? in_key[5] : k2_1);\r
+\r
+ lk[6] = io_swap(key_len > 192 ? in_key[6] : k3_0);\r
+ lk[7] = io_swap(key_len > 192 ? in_key[7] : k3_1);\r
+\r
+ g_fun(lk, lout, v);\r
+\r
+ for(i = 0; i < 8; ++i)\r
+ {\r
+ g_fun(lk, lout, v);\r
+\r
+ for(j = 0; j < 4; ++j)\r
+ {\r
+ // this is complex because of a byte swap in each 32 bit output word\r
+\r
+ k = 2 * (48 - 16 * j + 2 * (i / 2) - i % 2);\r
+\r
+ ((u1byte*)l_key)[k + 3] = ((u1byte*)lout)[j];\r
+ ((u1byte*)l_key)[k + 2] = ((u1byte*)lout)[j + 16];\r
+\r
+ ((u1byte*)l_key)[k + 19] = ((u1byte*)lout)[j + 8];\r
+ ((u1byte*)l_key)[k + 18] = ((u1byte*)lout)[j + 24];\r
+\r
+ ((u1byte*)l_key)[k + 131] = ((u1byte*)lout)[j + 4];\r
+ ((u1byte*)l_key)[k + 130] = ((u1byte*)lout)[j + 20];\r
+\r
+ ((u1byte*)l_key)[k + 147] = ((u1byte*)lout)[j + 12];\r
+ ((u1byte*)l_key)[k + 146] = ((u1byte*)lout)[j + 28];\r
+ }\r
+ }\r
+\r
+ for(i = 52; i < 60; ++i)\r
+ {\r
+ l_key[i] |= 1; l_key[i + 12] = mod_inv(l_key[i]);\r
+ }\r
+\r
+ for(i = 0; i < 48; i += 4)\r
+ {\r
+ bp2_fun(l_key[i], l_key[i + 1]);\r
+ }\r
+\r
+ return (u4byte*)&l_key;\r
+};\r
+\r
+void e2_encrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte a,b,c,d,p,q,r,s,u,v;\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ p = io_swap(in_blk[0]); q = io_swap(in_blk[1]); \r
+ r = io_swap(in_blk[2]); s = io_swap(in_blk[3]);\r
+ \r
+ p ^= l_key[48]; q ^= l_key[49]; r ^= l_key[50]; s ^= l_key[51]; \r
+ p *= l_key[52]; q *= l_key[53]; r *= l_key[54]; s *= l_key[55];\r
+\r
+ bp_fun(a, b, c, d, p, q, r, s);\r
+\r
+ f_fun(a, b, c, d, l_key);\r
+ f_fun(c, d, a, b, l_key + 4);\r
+ f_fun(a, b, c, d, l_key + 8);\r
+ f_fun(c, d, a, b, l_key + 12);\r
+ f_fun(a, b, c, d, l_key + 16);\r
+ f_fun(c, d, a, b, l_key + 20);\r
+ f_fun(a, b, c, d, l_key + 24);\r
+ f_fun(c, d, a, b, l_key + 28);\r
+ f_fun(a, b, c, d, l_key + 32);\r
+ f_fun(c, d, a, b, l_key + 36);\r
+ f_fun(a, b, c, d, l_key + 40);\r
+ f_fun(c, d, a, b, l_key + 44);\r
+\r
+ ibp_fun(p, q, r, s, a, b, c, d); \r
+ \r
+ p *= l_key[68]; q *= l_key[69]; r *= l_key[70]; s *= l_key[71]; \r
+ p ^= l_key[60]; q ^= l_key[61]; r ^= l_key[62]; s ^= l_key[63];\r
+ \r
+ out_blk[0] = io_swap(p); out_blk[1] = io_swap(q);\r
+ out_blk[2] = io_swap(r); out_blk[3] = io_swap(s);\r
+};\r
+\r
+void e2_decrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte a,b,c,d,p,q,r,s,u,v;\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ p = io_swap(in_blk[0]); q = io_swap(in_blk[1]); \r
+ r = io_swap(in_blk[2]); s = io_swap(in_blk[3]);\r
+\r
+ p ^= l_key[60]; q ^= l_key[61]; r ^= l_key[62]; s ^= l_key[63];\r
+ p *= l_key[56]; q *= l_key[57]; r *= l_key[58]; s *= l_key[59];\r
+\r
+ bp_fun(a, b, c, d, p, q, r, s);\r
+\r
+ f_fun(a, b, c, d, l_key + 44);\r
+ f_fun(c, d, a, b, l_key + 40);\r
+\r
+ f_fun(a, b, c, d, l_key + 36);\r
+ f_fun(c, d, a, b, l_key + 32);\r
+\r
+ f_fun(a, b, c, d, l_key + 28);\r
+ f_fun(c, d, a, b, l_key + 24);\r
+ \r
+ f_fun(a, b, c, d, l_key + 20);\r
+ f_fun(c, d, a, b, l_key + 16);\r
+\r
+ f_fun(a, b, c, d, l_key + 12);\r
+ f_fun(c, d, a, b, l_key + 8);\r
+ \r
+ f_fun(a, b, c, d, l_key + 4);\r
+ f_fun(c, d, a, b, l_key);\r
+\r
+ ibp_fun(p, q, r, s, a, b, c, d); \r
+ \r
+ p *= l_key[64]; q *= l_key[65]; r *= l_key[66]; s *= l_key[67]; \r
+ p ^= l_key[48]; q ^= l_key[49]; r ^= l_key[50]; s ^= l_key[51];\r
+\r
+ out_blk[0] = io_swap(p); out_blk[1] = io_swap(q); \r
+ out_blk[2] = io_swap(r); out_blk[3] = io_swap(s);\r
+};\r
--- /dev/null
+/*
+
+ e2.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef E2_H
+#define E2_H
+
+#include "e2_internal.h"
+
+/*
+ * SILC Crypto API for E2
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_e2_init(void *context,
+ const unsigned char *key,
+ size_t keylen)
+{
+ e2_set_key((E2Context *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+inline int silc_e2_set_string_as_key(void *context,
+ const unsigned char *string,
+ size_t keylen)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+
+ return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_e2_context_len()
+{
+ return sizeof(E2Context);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_e2_encrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ e2_encrypt((E2Context *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ e2_encrypt((E2Context *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_e2_decrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ e2_decrypt((E2Context *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ e2_decrypt((E2Context *)context, in, out);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+
+ e2_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef E2_INTERNAL_H
+#define E2_INTERNAL_H
+
+typedef struct {
+ u4byte l_key[72];
+} E2Context;
+
+/* Prototypes */
+u4byte *e2_set_key(E2Context *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void e2_encrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4]);
+void e2_decrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm: */\r
+/* */\r
+/* LOKI97 by Brown and Pieprzyk */\r
+/* */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard */\r
+/* programme of the US National Institute of Standards and Technology. */\r
+/* */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions */\r
+/* that the originators of the algorithm place on its exploitation. */\r
+/* */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */\r
+\r
+/* Timing data for LOKI97 (loki.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 7430 cycles\r
+Encrypt: 2134 cycles = 12.0 mbits/sec\r
+Decrypt: 2192 cycles = 11.7 mbits/sec\r
+Mean: 2163 cycles = 11.8 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 7303 cycles\r
+Encrypt: 2138 cycles = 12.0 mbits/sec\r
+Decrypt: 2189 cycles = 11.7 mbits/sec\r
+Mean: 2164 cycles = 11.8 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 7166 cycles\r
+Encrypt: 2131 cycles = 12.0 mbits/sec\r
+Decrypt: 2184 cycles = 11.7 mbits/sec\r
+Mean: 2158 cycles = 11.9 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 7582 cycles\r
+Encrypt: 2174 cycles = 11.8 mbits/sec\r
+Decrypt: 2235 cycles = 11.5 mbits/sec\r
+Mean: 2205 cycles = 11.6 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 7477 cycles\r
+Encrypt: 2167 cycles = 11.8 mbits/sec\r
+Decrypt: 2223 cycles = 11.5 mbits/sec\r
+Mean: 2195 cycles = 11.7 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 7365 cycles\r
+Encrypt: 2177 cycles = 11.8 mbits/sec\r
+Decrypt: 2194 cycles = 11.7 mbits/sec\r
+Mean: 2186 cycles = 11.7 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "loki_internal.h"\r
+\r
+#define S1_SIZE 13\r
+#define S1_LEN (1 << S1_SIZE)\r
+#define S1_MASK (S1_LEN - 1)\r
+#define S1_HMASK (S1_MASK & ~0xff)\r
+#define S1_POLY 0x2911\r
+\r
+#define S2_SIZE 11\r
+#define S2_LEN (1 << S2_SIZE)\r
+#define S2_MASK (S2_LEN - 1)\r
+#define S2_HMASK (S2_MASK & ~0xff)\r
+#define S2_POLY 0x0aa7\r
+\r
+#define io_swap(x) ((x))\r
+\r
+u4byte delta[2] = { 0x7f4a7c15, 0x9e3779b9 };\r
+\r
+u1byte sb1[S1_LEN]; // GF(2^11) S box\r
+u1byte sb2[S2_LEN]; // GF(2^11) S box\r
+u4byte prm[256][2];\r
+u4byte init_done = 0;\r
+\r
+#define add_eq(x,y) (x)[1] += (y)[1] + (((x)[0] += (y)[0]) < (y)[0] ? 1 : x)\r
+#define sub_eq(x,y) xs = (x)[0]; (x)[1] -= (y)[1] + (((x)[0] -= (y)[0]) > xs ? 1 : 0) \r
+\r
+u4byte ff_mult(u4byte a, u4byte b, u4byte tpow, u4byte mpol)\r
+{ u4byte r, s, m;\r
+\r
+ r = s = 0; m = (1 << tpow); \r
+\r
+ while(b)\r
+ {\r
+ if(b & 1)\r
+ \r
+ s ^= a;\r
+ \r
+ b >>= 1; a <<= 1;\r
+ \r
+ if(a & m)\r
+ \r
+ a ^= mpol;\r
+ }\r
+\r
+ return s;\r
+};\r
+\r
+void init_tables(void)\r
+{ u4byte i, j, v;\r
+\r
+ // initialise S box 1\r
+\r
+ for(i = 0; i < S1_LEN; ++i)\r
+ {\r
+ j = v = i ^ S1_MASK; v = ff_mult(v, j, S1_SIZE, S1_POLY);\r
+ sb1[i] = (u1byte)ff_mult(v, j, S1_SIZE, S1_POLY);\r
+ } \r
+ // initialise S box 2\r
+\r
+ for(i = 0; i < S2_LEN; ++i)\r
+ {\r
+ j = v = i ^ S2_MASK; v = ff_mult(v, j, S2_SIZE, S2_POLY);\r
+ sb2[i] = (u1byte)ff_mult(v, j, S2_SIZE, S2_POLY);\r
+ }\r
+\r
+ // initialise permutation table\r
+\r
+ for(i = 0; i < 256; ++i)\r
+ {\r
+ prm[i][0] = ((i & 1) << 7) | ((i & 2) << 14) | ((i & 4) << 21) | ((i & 8) << 28);\r
+ prm[i][1] = ((i & 16) << 3) | ((i & 32) << 10) | ((i & 64) << 17) | ((i & 128) << 24);\r
+ }\r
+};\r
+\r
+void f_fun(u4byte res[2], const u4byte in[2], const u4byte key[2])\r
+{ u4byte i, tt[2], pp[2];\r
+\r
+ tt[0] = (in[0] & ~key[0]) | (in[1] & key[0]);\r
+ tt[1] = (in[1] & ~key[0]) | (in[0] & key[0]);\r
+\r
+ i = sb1[((tt[1] >> 24) | (tt[0] << 8)) & S1_MASK];\r
+ pp[0] = prm[i][0] >> 7; pp[1] = prm[i][1] >> 7;\r
+ i = sb2[(tt[1] >> 16) & S2_MASK];\r
+ pp[0] |= prm[i][0] >> 6; pp[1] |= prm[i][1] >> 6;\r
+ i = sb1[(tt[1] >> 8) & S1_MASK];\r
+ pp[0] |= prm[i][0] >> 5; pp[1] |= prm[i][1] >> 5;\r
+ i = sb2[tt[1] & S2_MASK]; \r
+ pp[0] |= prm[i][0] >> 4; pp[1] |= prm[i][1] >> 4;\r
+ i = sb2[((tt[0] >> 24) | (tt[1] << 8)) & S2_MASK];\r
+ pp[0] |= prm[i][0] >> 3; pp[1] |= prm[i][1] >> 3;\r
+ i = sb1[(tt[0] >> 16) & S1_MASK]; \r
+ pp[0] |= prm[i][0] >> 2; pp[1] |= prm[i][1] >> 2;\r
+ i = sb2[(tt[0] >> 8) & S2_MASK]; \r
+ pp[0] |= prm[i][0] >> 1; pp[1] |= prm[i][1] >> 1;\r
+ i = sb1[tt[0] & S1_MASK]; \r
+ pp[0] |= prm[i][0]; pp[1] |= prm[i][1];\r
+\r
+ res[0] ^= sb1[byte(pp[0], 0) | (key[1] << 8) & S1_HMASK]\r
+ | (sb1[byte(pp[0], 1) | (key[1] << 3) & S1_HMASK] << 8)\r
+ | (sb2[byte(pp[0], 2) | (key[1] >> 2) & S2_HMASK] << 16)\r
+ | (sb2[byte(pp[0], 3) | (key[1] >> 5) & S2_HMASK] << 24);\r
+ res[1] ^= sb1[byte(pp[1], 0) | (key[1] >> 8) & S1_HMASK]\r
+ | (sb1[byte(pp[1], 1) | (key[1] >> 13) & S1_HMASK] << 8)\r
+ | (sb2[byte(pp[1], 2) | (key[1] >> 18) & S2_HMASK] << 16)\r
+ | (sb2[byte(pp[1], 3) | (key[1] >> 21) & S2_HMASK] << 24);\r
+};\r
+\r
+u4byte *loki_set_key(LokiContext *ctx,\r
+ const u4byte in_key[], const u4byte key_len)\r
+{ \r
+ u4byte i, k1[2], k2[2], k3[2], k4[2], del[2], tt[2], sk[2];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ if(!init_done)\r
+ {\r
+ init_tables(); init_done = 1;\r
+ }\r
+\r
+ k4[0] = io_swap(in_key[1]); k4[1] = io_swap(in_key[0]);\r
+ k3[0] = io_swap(in_key[3]); k3[1] = io_swap(in_key[2]);\r
+\r
+ switch ((key_len + 63) / 64)\r
+ {\r
+ case 2:\r
+ k2[0] = 0; k2[1] = 0; f_fun(k2, k3, k4);\r
+ k1[0] = 0; k1[1] = 0; f_fun(k1, k4, k3);\r
+ break;\r
+ case 3:\r
+ k2[0] = io_swap(in_key[5]); k2[1] = io_swap(in_key[4]);\r
+ k1[0] = 0; k1[1] = 0; f_fun(k1, k4, k3);\r
+ break;\r
+ case 4: \r
+ k2[0] = in_key[5]; k2[1] = in_key[4];\r
+ k1[0] = in_key[7]; k1[1] = in_key[6];\r
+ k2[0] = io_swap(in_key[5]); k2[1] = io_swap(in_key[4]);\r
+ k1[0] = io_swap(in_key[7]); k1[1] = io_swap(in_key[6]);\r
+ }\r
+\r
+ del[0] = delta[0]; del[1] = delta[1];\r
+\r
+ for(i = 0; i < 48; ++i)\r
+ {\r
+ tt[0] = k1[0]; tt[1] = k1[1]; \r
+ add_eq(tt, k3); add_eq(tt, del); add_eq(del, delta);\r
+ sk[0] = k4[0]; sk[1] = k4[1];\r
+ k4[0] = k3[0]; k4[1] = k3[1];\r
+ k3[0] = k2[0]; k3[1] = k2[1];\r
+ k2[0] = k1[0]; k2[1] = k1[1];\r
+ k1[0] = sk[0]; k1[1] = sk[1];\r
+ f_fun(k1, tt, k3);\r
+ l_key[i + i] = k1[0]; l_key[i + i + 1] = k1[1];\r
+ }\r
+\r
+ return l_key;\r
+};\r
+\r
+#define r_fun(l,r,k) \\r
+ add_eq((l),(k)); \\r
+ f_fun((r),(l),(k) + 2); \\r
+ add_eq((l), (k) + 4)\r
+\r
+void loki_encrypt(LokiContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte blk[4];\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ blk[3] = io_swap(in_blk[0]); blk[2] = io_swap(in_blk[1]);\r
+ blk[1] = io_swap(in_blk[2]); blk[0] = io_swap(in_blk[3]);\r
+\r
+ r_fun(blk, blk + 2, l_key + 0);\r
+ r_fun(blk + 2, blk, l_key + 6);\r
+ r_fun(blk, blk + 2, l_key + 12);\r
+ r_fun(blk + 2, blk, l_key + 18);\r
+ r_fun(blk, blk + 2, l_key + 24);\r
+ r_fun(blk + 2, blk, l_key + 30);\r
+ r_fun(blk, blk + 2, l_key + 36);\r
+ r_fun(blk + 2, blk, l_key + 42);\r
+ r_fun(blk, blk + 2, l_key + 48);\r
+ r_fun(blk + 2, blk, l_key + 54);\r
+ r_fun(blk, blk + 2, l_key + 60);\r
+ r_fun(blk + 2, blk, l_key + 66);\r
+ r_fun(blk, blk + 2, l_key + 72);\r
+ r_fun(blk + 2, blk, l_key + 78);\r
+ r_fun(blk, blk + 2, l_key + 84);\r
+ r_fun(blk + 2, blk, l_key + 90);\r
+\r
+ out_blk[3] = io_swap(blk[2]); out_blk[2] = io_swap(blk[3]);\r
+ out_blk[1] = io_swap(blk[0]); out_blk[0] = io_swap(blk[1]);\r
+};\r
+\r
+#define ir_fun(l,r,k) \\r
+ sub_eq((l),(k) + 4); \\r
+ f_fun((r),(l),(k) + 2); \\r
+ sub_eq((l),(k))\r
+\r
+void loki_decrypt(LokiContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte blk[4], xs;\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ blk[3] = io_swap(in_blk[0]); blk[2] = io_swap(in_blk[1]);\r
+ blk[1] = io_swap(in_blk[2]); blk[0] = io_swap(in_blk[3]);\r
+\r
+ ir_fun(blk, blk + 2, l_key + 90); \r
+ ir_fun(blk + 2, blk, l_key + 84);\r
+ ir_fun(blk, blk + 2, l_key + 78); \r
+ ir_fun(blk + 2, blk, l_key + 72);\r
+ ir_fun(blk, blk + 2, l_key + 66); \r
+ ir_fun(blk + 2, blk, l_key + 60);\r
+ ir_fun(blk, blk + 2, l_key + 54); \r
+ ir_fun(blk + 2, blk, l_key + 48);\r
+ ir_fun(blk, blk + 2, l_key + 42); \r
+ ir_fun(blk + 2, blk, l_key + 36);\r
+ ir_fun(blk, blk + 2, l_key + 30); \r
+ ir_fun(blk + 2, blk, l_key + 24);\r
+ ir_fun(blk, blk + 2, l_key + 18); \r
+ ir_fun(blk + 2, blk, l_key + 12);\r
+ ir_fun(blk, blk + 2, l_key + 6); \r
+ ir_fun(blk + 2, blk, l_key);\r
+\r
+ out_blk[3] = io_swap(blk[2]); out_blk[2] = io_swap(blk[3]);\r
+ out_blk[1] = io_swap(blk[0]); out_blk[0] = io_swap(blk[1]); \r
+};\r
--- /dev/null
+/*
+
+ loki.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef LOKI_H
+#define LOKI_H
+
+#include "loki_internal.h"
+
+/*
+ * SILC Crypto API for Loki
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_loki_init(void *context,
+ const unsigned char *key,
+ size_t keylen)
+{
+ loki_set_key((LokiContext *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string
+ is first hashed and then used as a new key. */
+
+inline int silc_loki_set_string_as_key(void *context,
+ const unsigned char *string,
+ size_t keylen)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+
+ return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_loki_context_len()
+{
+ return sizeof(LokiContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_loki_encrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ loki_encrypt((LokiContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ loki_encrypt((LokiContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_loki_decrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ loki_decrypt((LokiContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ loki_decrypt((LokiContext *)context, in, out);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+
+ loki_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef LOKI_INTERNAL_H
+#define LOKI_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+ u4byte l_key[96];
+} LokiContext;
+
+/* Prototypes */
+u4byte *loki_set_key(LokiContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void loki_encrypt(LokiContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void loki_decrypt(LokiContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm: */
+/* */
+/* MARS by a team at IBM, */
+/* */
+/* which is a candidate algorithm in the Advanced Encryption Standard */
+/* programme of the US National Institute of Standards and Technology. */
+/* Copyright in this implementation is held by Dr B R Gladman. The MARS */
+/* algorithm is covered by a pending patent application owned by IBM, */
+/* who intend to offer a royalty free license under any issued patent */
+/* that results from such application if MARS is selected as the AES */
+/* algorithm. In the interim, you may evaluate the MARS algorithm for */
+/* your personal, lawful, non-profit purposes as an end user. */
+/* */
+/* The header above modified on June 6th 1999. */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
+
+/* Timing data for MARS (mars.c)
+
+128 bit key:
+Key Setup: 4316 cycles
+Encrypt: 369 cycles = 69.4 mbits/sec
+Decrypt: 376 cycles = 68.1 mbits/sec
+Mean: 373 cycles = 68.7 mbits/sec
+
+192 bit key:
+Key Setup: 4377 cycles
+Encrypt: 373 cycles = 68.6 mbits/sec
+Decrypt: 379 cycles = 67.5 mbits/sec
+Mean: 376 cycles = 68.1 mbits/sec
+
+256 bit key:
+Key Setup: 4340 cycles
+Encrypt: 369 cycles = 69.4 mbits/sec
+Decrypt: 376 cycles = 68.1 mbits/sec
+Mean: 373 cycles = 68.7 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "mars.h"
+
+/*
+ * SILC Crypto API for MARS
+ */
+
+/* Sets the key for cipher MARS. */
+
+SILC_CIPHER_API_SET_KEY(mars)
+{
+ mars_set_key((MarsContext *)context, (unsigned int *)key, keylen);
+ return TRUE;
+}
+
+/* Sets the string as a new key for the cipher MARS. The string
+ is first hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(mars)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+ return TRUE;
+}
+
+/* Returns the size of the MARS cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(mars)
+{
+ return sizeof(MarsContext);
+}
+
+/* Encrypts with MARS cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(mars)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ mars_encrypt((MarsContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ mars_encrypt((MarsContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ tiv[0] = out[0 - 4];
+ tiv[1] = out[1 - 4];
+ tiv[2] = out[2 - 4];
+ tiv[3] = out[3 - 4];
+
+ return TRUE;
+}
+
+/* Decrypts with MARS cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(mars)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4], tmp2[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ mars_decrypt((MarsContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp2[0] = tmp[0];
+ tmp2[1] = tmp[1];
+ tmp2[2] = tmp[2];
+ tmp2[3] = tmp[3];
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ mars_decrypt((MarsContext *)context, in, out);
+ out[0] ^= tmp2[0];
+ out[1] ^= tmp2[1];
+ out[2] ^= tmp2[2];
+ out[3] ^= tmp2[3];
+ in += 4;
+ out += 4;
+ }
+
+ tiv[0] = tmp[0];
+ tiv[1] = tmp[1];
+ tiv[2] = tmp[2];
+ tiv[3] = tmp[3];
+
+ return TRUE;
+}
+
+static u4byte s_box[] =
+{
+ 0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, /* 0x000 */
+ 0x7dff9be3, 0xd4268361, 0xc96da1d4, 0x7974cc93,
+ 0x85d0582e, 0x2a4b5705, 0x1ca16a62, 0xc3bd279d,
+ 0x0f1f25e5, 0x5160372f, 0xc695c1fb, 0x4d7ff1e4,
+ 0xae5f6bf4, 0x0d72ee46, 0xff23de8a, 0xb1cf8e83, /* 0x010 */
+ 0xf14902e2, 0x3e981e42, 0x8bf53eb6, 0x7f4bf8ac,
+ 0x83631f83, 0x25970205, 0x76afe784, 0x3a7931d4,
+ 0x4f846450, 0x5c64c3f6, 0x210a5f18, 0xc6986a26,
+ 0x28f4e826, 0x3a60a81c, 0xd340a664, 0x7ea820c4, /* 0x020 */
+ 0x526687c5, 0x7eddd12b, 0x32a11d1d, 0x9c9ef086,
+ 0x80f6e831, 0xab6f04ad, 0x56fb9b53, 0x8b2e095c,
+ 0xb68556ae, 0xd2250b0d, 0x294a7721, 0xe21fb253,
+ 0xae136749, 0xe82aae86, 0x93365104, 0x99404a66, /* 0x030 */
+ 0x78a784dc, 0xb69ba84b, 0x04046793, 0x23db5c1e,
+ 0x46cae1d6, 0x2fe28134, 0x5a223942, 0x1863cd5b,
+ 0xc190c6e3, 0x07dfb846, 0x6eb88816, 0x2d0dcc4a,
+ 0xa4ccae59, 0x3798670d, 0xcbfa9493, 0x4f481d45, /* 0x040 */
+ 0xeafc8ca8, 0xdb1129d6, 0xb0449e20, 0x0f5407fb,
+ 0x6167d9a8, 0xd1f45763, 0x4daa96c3, 0x3bec5958,
+ 0xababa014, 0xb6ccd201, 0x38d6279f, 0x02682215,
+ 0x8f376cd5, 0x092c237e, 0xbfc56593, 0x32889d2c, /* 0x050 */
+ 0x854b3e95, 0x05bb9b43, 0x7dcd5dcd, 0xa02e926c,
+ 0xfae527e5, 0x36a1c330, 0x3412e1ae, 0xf257f462,
+ 0x3c4f1d71, 0x30a2e809, 0x68e5f551, 0x9c61ba44,
+ 0x5ded0ab8, 0x75ce09c8, 0x9654f93e, 0x698c0cca, /* 0x060 */
+ 0x243cb3e4, 0x2b062b97, 0x0f3b8d9e, 0x00e050df,
+ 0xfc5d6166, 0xe35f9288, 0xc079550d, 0x0591aee8,
+ 0x8e531e74, 0x75fe3578, 0x2f6d829a, 0xf60b21ae,
+ 0x95e8eb8d, 0x6699486b, 0x901d7d9b, 0xfd6d6e31, /* 0x070 */
+ 0x1090acef, 0xe0670dd8, 0xdab2e692, 0xcd6d4365,
+ 0xe5393514, 0x3af345f0, 0x6241fc4d, 0x460da3a3,
+ 0x7bcf3729, 0x8bf1d1e0, 0x14aac070, 0x1587ed55,
+ 0x3afd7d3e, 0xd2f29e01, 0x29a9d1f6, 0xefb10c53, /* 0x080 */
+ 0xcf3b870f, 0xb414935c, 0x664465ed, 0x024acac7,
+ 0x59a744c1, 0x1d2936a7, 0xdc580aa6, 0xcf574ca8,
+ 0x040a7a10, 0x6cd81807, 0x8a98be4c, 0xaccea063,
+ 0xc33e92b5, 0xd1e0e03d, 0xb322517e, 0x2092bd13, /* 0x090 */
+ 0x386b2c4a, 0x52e8dd58, 0x58656dfb, 0x50820371,
+ 0x41811896, 0xe337ef7e, 0xd39fb119, 0xc97f0df6,
+ 0x68fea01b, 0xa150a6e5, 0x55258962, 0xeb6ff41b,
+ 0xd7c9cd7a, 0xa619cd9e, 0xbcf09576, 0x2672c073, /* 0x0a0 */
+ 0xf003fb3c, 0x4ab7a50b, 0x1484126a, 0x487ba9b1,
+ 0xa64fc9c6, 0xf6957d49, 0x38b06a75, 0xdd805fcd,
+ 0x63d094cf, 0xf51c999e, 0x1aa4d343, 0xb8495294,
+ 0xce9f8e99, 0xbffcd770, 0xc7c275cc, 0x378453a7, /* 0x0b0 */
+ 0x7b21be33, 0x397f41bd, 0x4e94d131, 0x92cc1f98,
+ 0x5915ea51, 0x99f861b7, 0xc9980a88, 0x1d74fd5f,
+ 0xb0a495f8, 0x614deed0, 0xb5778eea, 0x5941792d,
+ 0xfa90c1f8, 0x33f824b4, 0xc4965372, 0x3ff6d550, /* 0x0c0 */
+ 0x4ca5fec0, 0x8630e964, 0x5b3fbbd6, 0x7da26a48,
+ 0xb203231a, 0x04297514, 0x2d639306, 0x2eb13149,
+ 0x16a45272, 0x532459a0, 0x8e5f4872, 0xf966c7d9,
+ 0x07128dc0, 0x0d44db62, 0xafc8d52d, 0x06316131, /* 0x0d0 */
+ 0xd838e7ce, 0x1bc41d00, 0x3a2e8c0f, 0xea83837e,
+ 0xb984737d, 0x13ba4891, 0xc4f8b949, 0xa6d6acb3,
+ 0xa215cdce, 0x8359838b, 0x6bd1aa31, 0xf579dd52,
+ 0x21b93f93, 0xf5176781, 0x187dfdde, 0xe94aeb76, /* 0x0e0 */
+ 0x2b38fd54, 0x431de1da, 0xab394825, 0x9ad3048f,
+ 0xdfea32aa, 0x659473e3, 0x623f7863, 0xf3346c59,
+ 0xab3ab685, 0x3346a90b, 0x6b56443e, 0xc6de01f8,
+ 0x8d421fc0, 0x9b0ed10c, 0x88f1a1e9, 0x54c1f029, /* 0x0f0 */
+ 0x7dead57b, 0x8d7ba426, 0x4cf5178a, 0x551a7cca,
+ 0x1a9a5f08, 0xfcd651b9, 0x25605182, 0xe11fc6c3,
+ 0xb6fd9676, 0x337b3027, 0xb7c8eb14, 0x9e5fd030,
+
+ 0x6b57e354, 0xad913cf7, 0x7e16688d, 0x58872a69, /* 0x100 */
+ 0x2c2fc7df, 0xe389ccc6, 0x30738df1, 0x0824a734,
+ 0xe1797a8b, 0xa4a8d57b, 0x5b5d193b, 0xc8a8309b,
+ 0x73f9a978, 0x73398d32, 0x0f59573e, 0xe9df2b03,
+ 0xe8a5b6c8, 0x848d0704, 0x98df93c2, 0x720a1dc3, /* 0x110 */
+ 0x684f259a, 0x943ba848, 0xa6370152, 0x863b5ea3,
+ 0xd17b978b, 0x6d9b58ef, 0x0a700dd4, 0xa73d36bf,
+ 0x8e6a0829, 0x8695bc14, 0xe35b3447, 0x933ac568,
+ 0x8894b022, 0x2f511c27, 0xddfbcc3c, 0x006662b6, /* 0x120 */
+ 0x117c83fe, 0x4e12b414, 0xc2bca766, 0x3a2fec10,
+ 0xf4562420, 0x55792e2a, 0x46f5d857, 0xceda25ce,
+ 0xc3601d3b, 0x6c00ab46, 0xefac9c28, 0xb3c35047,
+ 0x611dfee3, 0x257c3207, 0xfdd58482, 0x3b14d84f, /* 0x130 */
+ 0x23becb64, 0xa075f3a3, 0x088f8ead, 0x07adf158,
+ 0x7796943c, 0xfacabf3d, 0xc09730cd, 0xf7679969,
+ 0xda44e9ed, 0x2c854c12, 0x35935fa3, 0x2f057d9f,
+ 0x690624f8, 0x1cb0bafd, 0x7b0dbdc6, 0x810f23bb, /* 0x140 */
+ 0xfa929a1a, 0x6d969a17, 0x6742979b, 0x74ac7d05,
+ 0x010e65c4, 0x86a3d963, 0xf907b5a0, 0xd0042bd3,
+ 0x158d7d03, 0x287a8255, 0xbba8366f, 0x096edc33,
+ 0x21916a7b, 0x77b56b86, 0x951622f9, 0xa6c5e650, /* 0x150 */
+ 0x8cea17d1, 0xcd8c62bc, 0xa3d63433, 0x358a68fd,
+ 0x0f9b9d3c, 0xd6aa295b, 0xfe33384a, 0xc000738e,
+ 0xcd67eb2f, 0xe2eb6dc2, 0x97338b02, 0x06c9f246,
+ 0x419cf1ad, 0x2b83c045, 0x3723f18a, 0xcb5b3089, /* 0x160 */
+ 0x160bead7, 0x5d494656, 0x35f8a74b, 0x1e4e6c9e,
+ 0x000399bd, 0x67466880, 0xb4174831, 0xacf423b2,
+ 0xca815ab3, 0x5a6395e7, 0x302a67c5, 0x8bdb446b,
+ 0x108f8fa4, 0x10223eda, 0x92b8b48b, 0x7f38d0ee, /* 0x170 */
+ 0xab2701d4, 0x0262d415, 0xaf224a30, 0xb3d88aba,
+ 0xf8b2c3af, 0xdaf7ef70, 0xcc97d3b7, 0xe9614b6c,
+ 0x2baebff4, 0x70f687cf, 0x386c9156, 0xce092ee5,
+ 0x01e87da6, 0x6ce91e6a, 0xbb7bcc84, 0xc7922c20, /* 0x180 */
+ 0x9d3b71fd, 0x060e41c6, 0xd7590f15, 0x4e03bb47,
+ 0x183c198e, 0x63eeb240, 0x2ddbf49a, 0x6d5cba54,
+ 0x923750af, 0xf9e14236, 0x7838162b, 0x59726c72,
+ 0x81b66760, 0xbb2926c1, 0x48a0ce0d, 0xa6c0496d, /* 0x190 */
+ 0xad43507b, 0x718d496a, 0x9df057af, 0x44b1bde6,
+ 0x054356dc, 0xde7ced35, 0xd51a138b, 0x62088cc9,
+ 0x35830311, 0xc96efca2, 0x686f86ec, 0x8e77cb68,
+ 0x63e1d6b8, 0xc80f9778, 0x79c491fd, 0x1b4c67f2, /* 0x1a0 */
+ 0x72698d7d, 0x5e368c31, 0xf7d95e2e, 0xa1d3493f,
+ 0xdcd9433e, 0x896f1552, 0x4bc4ca7a, 0xa6d1baf4,
+ 0xa5a96dcc, 0x0bef8b46, 0xa169fda7, 0x74df40b7,
+ 0x4e208804, 0x9a756607, 0x038e87c8, 0x20211e44, /* 0x1b0 */
+ 0x8b7ad4bf, 0xc6403f35, 0x1848e36d, 0x80bdb038,
+ 0x1e62891c, 0x643d2107, 0xbf04d6f8, 0x21092c8c,
+ 0xf644f389, 0x0778404e, 0x7b78adb8, 0xa2c52d53,
+ 0x42157abe, 0xa2253e2e, 0x7bf3f4ae, 0x80f594f9, /* 0x1c0 */
+ 0x953194e7, 0x77eb92ed, 0xb3816930, 0xda8d9336,
+ 0xbf447469, 0xf26d9483, 0xee6faed5, 0x71371235,
+ 0xde425f73, 0xb4e59f43, 0x7dbe2d4e, 0x2d37b185,
+ 0x49dc9a63, 0x98c39d98, 0x1301c9a2, 0x389b1bbf, /* 0x1d0 */
+ 0x0c18588d, 0xa421c1ba, 0x7aa3865c, 0x71e08558,
+ 0x3c5cfcaa, 0x7d239ca4, 0x0297d9dd, 0xd7dc2830,
+ 0x4b37802b, 0x7428ab54, 0xaeee0347, 0x4b3fbb85,
+ 0x692f2f08, 0x134e578e, 0x36d9e0bf, 0xae8b5fcf, /* 0x1e0 */
+ 0xedb93ecf, 0x2b27248e, 0x170eb1ef, 0x7dc57fd6,
+ 0x1e760f16, 0xb1136601, 0x864e1b9b, 0xd7ea7319,
+ 0x3ab871bd, 0xcfa4d76f, 0xe31bd782, 0x0dbeb469,
+ 0xabb96061, 0x5370f85d, 0xffb07e37, 0xda30d0fb, /* 0x1f0 */
+ 0xebc977b6, 0x0b98b40f, 0x3a4d0fe6, 0xdf4fc26b,
+ 0x159cf22a, 0xc298d6e2, 0x2b78ef6a, 0x61a94ac0,
+ 0xab561187, 0x14eea0f0, 0xdf0d4164, 0x19af70ee
+};
+
+static u4byte vk[47] =
+{
+ 0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, 0x7dff9be3, 0xd4268361,
+ 0xc96da1d4
+};
+
+#define f_mix(a,b,c,d) \
+ r = rotr(a, 8); \
+ b ^= s_box[a & 255]; \
+ b += s_box[(r & 255) + 256]; \
+ r = rotr(a, 16); \
+ a = rotr(a, 24); \
+ c += s_box[r & 255]; \
+ d ^= s_box[(a & 255) + 256]
+
+#define b_mix(a,b,c,d) \
+ r = rotl(a, 8); \
+ b ^= s_box[(a & 255) + 256]; \
+ c -= s_box[r & 255]; \
+ r = rotl(a, 16); \
+ a = rotl(a, 24); \
+ d -= s_box[(r & 255) + 256]; \
+ d ^= s_box[a & 255]
+
+#define f_ktr(a,b,c,d,i) \
+ m = a + l_key[i]; \
+ a = rotl(a, 13); \
+ r = a * l_key[i + 1]; \
+ l = s_box[m & 511]; \
+ r = rotl(r, 5); \
+ c += rotl(m, r); \
+ l ^= r; \
+ r = rotl(r, 5); \
+ l ^= r; \
+ d ^= r; \
+ b += rotl(l, r)
+
+#define r_ktr(a,b,c,d,i) \
+ r = a * l_key[i + 1]; \
+ a = rotr(a, 13); \
+ m = a + l_key[i]; \
+ l = s_box[m & 511]; \
+ r = rotl(r, 5); \
+ l ^= r; \
+ c -= rotl(m, r); \
+ r = rotl(r, 5); \
+ l ^= r; \
+ d ^= r; \
+ b -= rotl(l, r)
+
+/* For a 32 bit word (x) generate a mask (m) such that a bit in */
+/* m is set to 1 if and only if the corresponding bit in x is: */
+/* */
+/* 1. in a sequence of 10 or more adjacent '0' bits */
+/* 2. in a sequence of 10 or more adjacent '1' bits */
+/* 3. but is not either endpoint of such a sequence unless such */
+/* an endpoint is at the top bit (bit 31) of a word and is */
+/* in a sequence of '0' bits. */
+/* */
+/* The only situation in which a sequence endpoint is included */
+/* in the mask is hence when the endpoint is at bit 31 and is */
+/* the endpoint of a sequence of '0' bits. My thanks go to Shai */
+/* Halevi of IBM for the neat trick (which I missed) of finding */
+/* the '0' and '1' sequences at the same time. */
+
+u4byte gen_mask(u4byte x)
+{ u4byte m;
+
+ /* if m{bn} stands for bit number bn of m, set m{bn} = 1 if */
+ /* x{bn} == x{bn+1} for 0 <= bn <= 30. That is, set a bit */
+ /* in m if the corresponding bit and the next higher bit in */
+ /* x are equal in value (set m{31} = 0). */
+
+ m = (~x ^ (x >> 1)) & 0x7fffffff;
+
+ /* Sequences of 9 '1' bits in m now correspond to sequences */
+ /* of 10 '0's or 10 '1' bits in x. Shift and 'and' bits in */
+ /* m to find sequences of 9 or more '1' bits. As a result */
+ /* bits in m are set if they are at the bottom of sequences */
+ /* of 10 adjacent '0's or 10 adjacent '1's in x. */
+
+ m &= (m >> 1) & (m >> 2); m &= (m >> 3) & (m >> 6);
+
+ if(!m) /* return if mask is empty - no key fixing needed */
+ /* is this early return worthwhile? */
+ return 0;
+
+ /* We need the internal bits in each continuous sequence of */
+ /* matching bits (that is the bits less the two endpoints). */
+ /* We thus propagate each set bit into the 8 internal bits */
+ /* that it represents, starting 1 left and finsihing 8 left */
+ /* of its position. */
+
+ m <<= 1; m |= (m << 1); m |= (m << 2); m |= (m << 4);
+
+ /* m is now correct except for the odd behaviour of bit 31, */
+ /* that is, it will be set if it is in a sequence of 10 or */
+ /* more '0's and clear otherwise. */
+
+ m |= (m << 1) & ~x & 0x80000000;
+
+ return m & 0xfffffffc;
+};
+
+/* My thanks to Louis Granboulan for spotting an error in the */
+/* previous version of set_key. */
+
+u4byte *mars_set_key(MarsContext *ctx,
+ const u4byte in_key[], const u4byte key_len)
+{
+ u4byte i, j, m, w;
+ u4byte *l_key = ctx->l_key;
+
+ m = key_len / 32 - 1;
+
+ for(i = j = 0; i < 39; ++i)
+ {
+ vk[i + 7] = rotl(vk[i] ^ vk[i + 5], 3) ^ in_key[j] ^ i;
+
+ j = (j == m ? 0 : j + 1);
+ }
+
+ vk[46] = key_len / 32;
+
+ for(j = 0; j < 7; ++j)
+ {
+ for(i = 1; i < 40; ++i)
+
+ vk[i + 7] = rotl(vk[i + 7] + s_box[vk[i + 6] & 511], 9);
+
+ vk[7] = rotl(vk[7] + s_box[vk[46] & 511], 9);
+ }
+
+ for(i = j = 0; i < 40; ++i)
+ {
+ l_key[j] = vk[i + 7];
+
+ j = (j < 33 ? j + 7 : j - 33);
+ }
+
+ for(i = 5; i < 37; i += 2)
+ {
+ w = l_key[i] | 3;
+
+ if((m = gen_mask(w)))
+
+ w ^= (rotl(s_box[265 + (l_key[i] & 3)], l_key[i + 3] & 31) & m);
+
+ l_key[i] = w;
+ }
+
+ return l_key;
+};
+
+void mars_encrypt(MarsContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte a, b, c, d, l, m, r;
+ u4byte *l_key = ctx->l_key;
+
+ a = in_blk[0] + l_key[0]; b = in_blk[1] + l_key[1];
+ c = in_blk[2] + l_key[2]; d = in_blk[3] + l_key[3];
+
+ f_mix(a,b,c,d); a += d;
+ f_mix(b,c,d,a); b += c;
+ f_mix(c,d,a,b);
+ f_mix(d,a,b,c);
+ f_mix(a,b,c,d); a += d;
+ f_mix(b,c,d,a); b += c;
+ f_mix(c,d,a,b);
+ f_mix(d,a,b,c);
+
+ f_ktr(a,b,c,d, 4); f_ktr(b,c,d,a, 6); f_ktr(c,d,a,b, 8); f_ktr(d,a,b,c,10);
+ f_ktr(a,b,c,d,12); f_ktr(b,c,d,a,14); f_ktr(c,d,a,b,16); f_ktr(d,a,b,c,18);
+ f_ktr(a,d,c,b,20); f_ktr(b,a,d,c,22); f_ktr(c,b,a,d,24); f_ktr(d,c,b,a,26);
+ f_ktr(a,d,c,b,28); f_ktr(b,a,d,c,30); f_ktr(c,b,a,d,32); f_ktr(d,c,b,a,34);
+
+ b_mix(a,b,c,d);
+ b_mix(b,c,d,a); c -= b;
+ b_mix(c,d,a,b); d -= a;
+ b_mix(d,a,b,c);
+ b_mix(a,b,c,d);
+ b_mix(b,c,d,a); c -= b;
+ b_mix(c,d,a,b); d -= a;
+ b_mix(d,a,b,c);
+
+ out_blk[0] = a - l_key[36]; out_blk[1] = b - l_key[37];
+ out_blk[2] = c - l_key[38]; out_blk[3] = d - l_key[39];
+};
+
+void mars_decrypt(MarsContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte a, b, c, d, l, m, r;
+ u4byte *l_key = ctx->l_key;
+
+ d = in_blk[0] + l_key[36]; c = in_blk[1] + l_key[37];
+ b = in_blk[2] + l_key[38]; a = in_blk[3] + l_key[39];
+
+ f_mix(a,b,c,d); a += d;
+ f_mix(b,c,d,a); b += c;
+ f_mix(c,d,a,b);
+ f_mix(d,a,b,c);
+ f_mix(a,b,c,d); a += d;
+ f_mix(b,c,d,a); b += c;
+ f_mix(c,d,a,b);
+ f_mix(d,a,b,c);
+
+ r_ktr(a,b,c,d,34); r_ktr(b,c,d,a,32); r_ktr(c,d,a,b,30); r_ktr(d,a,b,c,28);
+ r_ktr(a,b,c,d,26); r_ktr(b,c,d,a,24); r_ktr(c,d,a,b,22); r_ktr(d,a,b,c,20);
+ r_ktr(a,d,c,b,18); r_ktr(b,a,d,c,16); r_ktr(c,b,a,d,14); r_ktr(d,c,b,a,12);
+ r_ktr(a,d,c,b,10); r_ktr(b,a,d,c, 8); r_ktr(c,b,a,d, 6); r_ktr(d,c,b,a, 4);
+
+ b_mix(a,b,c,d);
+ b_mix(b,c,d,a); c -= b;
+ b_mix(c,d,a,b); d -= a;
+ b_mix(d,a,b,c);
+ b_mix(a,b,c,d);
+ b_mix(b,c,d,a); c -= b;
+ b_mix(c,d,a,b); d -= a;
+ b_mix(d,a,b,c);
+
+ out_blk[0] = d - l_key[0]; out_blk[1] = c - l_key[1];
+ out_blk[2] = b - l_key[2]; out_blk[3] = a - l_key[3];
+}
--- /dev/null
+/*
+
+ mars.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef MARS_H
+#define MARS_H
+
+#include "mars_internal.h"
+
+/*
+ * SILC Crypto API for MARS
+ */
+
+SILC_CIPHER_API_SET_KEY(mars);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(mars);
+SILC_CIPHER_API_CONTEXT_LEN(mars);
+SILC_CIPHER_API_ENCRYPT_CBC(mars);
+SILC_CIPHER_API_DECRYPT_CBC(mars);
+
+#endif
--- /dev/null
+/*
+
+ mars_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef MARS_INTERNAL_H
+#define MARS_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher context */
+typedef struct {
+ u4byte l_key[40];
+} MarsContext;
+
+/* Prototypes */
+u4byte *mars_set_key(MarsContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void mars_encrypt(MarsContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void mars_decrypt(MarsContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/* File ripped from noiz-0.5 */
+/* Modified by Pekka Riikonen (priikone@poseidon.pspt.fi) */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "silcincludes.h"
+#include "md5.h"
+
+/*
+ * SILC Hash API for MD5
+ */
+
+SILC_HASH_API_INIT(md5)
+{
+ MD5Init((struct MD5Context *)context);
+}
+
+SILC_HASH_API_UPDATE(md5)
+{
+ MD5Update((struct MD5Context *)context, data, len);
+}
+
+SILC_HASH_API_FINAL(md5)
+{
+ MD5Final(digest, (struct MD5Context *)context);
+}
+
+SILC_HASH_API_TRANSFORM(md5)
+{
+ MD5Transform(state, buffer);
+}
+
+SILC_HASH_API_CONTEXT_LEN(md5)
+{
+ return sizeof(struct MD5Context);
+}
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
+ ((unsigned)buf[1]<<8 | buf[0]);
+ *(uint32 *)buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = (unsigned char *)ctx->in + t;
+
+ t = 64-t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count-8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
+ ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, ctx->in);
+ byteReverse((unsigned char *)ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32 buf[4], const unsigned char kbuf[64])
+{
+ register uint32 a, b, c, d, i;
+ uint32 in[16];
+
+ for (i = 0; i < 16; i++)
+ SILC_GET32_MSB(in[i], kbuf + 4 * i);
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+#endif
--- /dev/null
+/*
+
+ md5.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#include "md5_internal.h"
+
+/*
+ * SILC Hash API for MD5
+ */
+
+SILC_HASH_API_INIT(md5);
+SILC_HASH_API_UPDATE(md5);
+SILC_HASH_API_FINAL(md5);
+SILC_HASH_API_TRANSFORM(md5);
+SILC_HASH_API_CONTEXT_LEN(md5);
+
+#endif
--- /dev/null
+/* file ripped from noiz-0.5. -Pekka */
+
+#ifndef MD5_INTERNAL_H
+#define MD5_INTERNAL_H
+
+typedef unsigned long uint32;
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], const unsigned char kbuf[64]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif
--- /dev/null
+/*
+
+ none.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "none.h"
+
+/*
+ * SILC Crypto API for None cipher (ie. no cipher) :)
+ */
+
+SILC_CIPHER_API_SET_KEY(none)
+{
+ return TRUE;
+}
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(none)
+{
+ return TRUE;
+}
+
+SILC_CIPHER_API_CONTEXT_LEN(none)
+{
+ return 1;
+}
+
+SILC_CIPHER_API_ENCRYPT_CBC(none)
+{
+ memcpy(dst, src, len);
+ return TRUE;
+}
+
+SILC_CIPHER_API_DECRYPT_CBC(none)
+{
+ memcpy(dst, src, len);
+ return TRUE;
+}
--- /dev/null
+/*
+
+ none.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef NONE_H
+#define NONE_H
+
+/*
+ * SILC Crypto API for None cipher (ie. no cipher) :)
+ */
+
+SILC_CIPHER_API_SET_KEY(none);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(none);
+SILC_CIPHER_API_CONTEXT_LEN(none);
+SILC_CIPHER_API_ENCRYPT_CBC(none);
+SILC_CIPHER_API_DECRYPT_CBC(none);
+
+#endif
--- /dev/null
+/*
+ * rc5.c RC5-32/16/b
+ *
+ * Copyright (c) 1999 Pekka Riikonen <priikone@poseidon.pspt.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, dis-
+ * tribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the fol-
+ * lowing conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+ * SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABIL-
+ * ITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the authors shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * the authors.
+ *
+ */
+
+/*
+ * Based on RC5 reference code and on description of Bruce Schneier's
+ * Applied Cryptography.
+ *
+ * This implementation has a word size of 32 bits, a rounds of 16 and
+ * variable key length from 128 and 192 up to 256 bits.
+ *
+ */
+
+#include "silcincludes.h"
+#include "rc5.h"
+
+/* RC5 encryption */
+#define RC5E(i, A, B) \
+ A = A ^ B; \
+ A = rotl(A, B) + S[i]; \
+ B = B ^ A; \
+ B = rotl(B, A) + S[i + 1];
+
+/* RC5 decryption */
+#define RC5D(i, A, B) \
+ B = B - S[i + 1]; \
+ B = rotr(B, A) ^ A; \
+ A = A - S[i]; \
+ A = rotr(A, B) ^ B;
+
+/* Sets RC5 key */
+
+int rc5_set_key(RC5Context *ctx, char *key, int key_len)
+{
+ u32 *in_key = (u32 *)key;
+ u32 i, j, k, A, B, L[c];
+ u32 *out_key = ctx->out_key;
+
+ if (key_len < b || key_len > (2 * b))
+ return -1;
+
+ // key_len *= 8;
+
+ /* init L */
+ for (i = 0; i < key_len / w; i++)
+ L[i] = in_key[i];
+
+ /* init key array (S) */
+ out_key[0] = 0xb7e15163;
+ for (i = 1; i < t; i++)
+ out_key[i] = out_key[i - 1] + 0x9e3779b9;
+
+ /* mix L and key array (S) */
+ A = B = 0;
+ for (k = i = j = 0; k < (3 * t); k++) {
+ A = rotl(out_key[i] + (A + B), 3);
+ B += A;
+ B = rotl(L[j] + B, B);
+ out_key[i] = A;
+ L[j] = B;
+ i = (i + 1) % t;
+ j = (j + 1) % c;
+ }
+
+ return 0;
+}
+
+/* Encrypts *one* block at a time. */
+
+int rc5_encrypt(RC5Context *ctx, u32 *in, u32 *out)
+{
+ u32 A, B;
+ u32 *S = ctx->out_key;
+
+ A = in[0] + S[0];
+ B = in[1] + S[1];
+
+ RC5E(2, A, B); RC5E(4, A, B);
+ RC5E(6, A, B); RC5E(8, A, B);
+ RC5E(10, A, B); RC5E(12, A, B);
+ RC5E(14, A, B); RC5E(16, A, B);
+ RC5E(18, A, B); RC5E(20, A, B);
+ RC5E(22, A, B); RC5E(24, A, B);
+ RC5E(26, A, B); RC5E(28, A, B);
+ RC5E(30, A, B); RC5E(32, A, B);
+
+ out[0] = A;
+ out[1] = B;
+
+ return 0;
+}
+
+/* Decrypts *one* block at a time. */
+
+int rc5_decrypt(RC5Context *ctx, u32 *in, u32 *out)
+{
+ u32 A, B;
+ u32 *S = ctx->out_key;
+
+ A = in[0];
+ B = in[1];
+
+ RC5D(32, A, B); RC5D(30, A, B);
+ RC5D(28, A, B); RC5D(26, A, B);
+ RC5D(24, A, B); RC5D(22, A, B);
+ RC5D(20, A, B); RC5D(18, A, B);
+ RC5D(16, A, B); RC5D(14, A, B);
+ RC5D(12, A, B); RC5D(10, A, B);
+ RC5D(8, A, B); RC5D(6, A, B);
+ RC5D(4, A, B); RC5D(2, A, B);
+
+ out[0] = A - S[0];
+ out[1] = B - S[1];
+
+ return 0;
+}
--- /dev/null
+/*
+
+ rc5.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef RC5_H
+#define RC5_H
+
+#include "rc5_internal.h"
+
+/*
+ * SILC Crypto API for RC5
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(rc5)
+{
+ rc5_set_key((RC5Context *)context, (unsigned char *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc5)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+
+ return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(rc5)
+{
+ return sizeof(RC5Context);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(rc5)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[2];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ rc5_encrypt((RC5Context *)context, tmp, out);
+ in += 2;
+ out += 2;
+
+ for (i = 8; i < len; i += 8) {
+ tmp[0] = in[0] ^ out[0 - 2];
+ tmp[1] = in[1] ^ out[1 - 2];
+ rc5_encrypt((RC5Context *)context, tmp, out);
+ in += 2;
+ out += 2;
+ }
+
+ return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_DECRYPT_CBC(rc5)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[2], tmp2[2];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[3] = in[3];
+ rc5_decrypt((RC5Context *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ in += 2;
+ out += 2;
+
+ for (i = 8; i < len; i += 8) {
+ tmp2[0] = tmp[0];
+ tmp2[1] = tmp[1];
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ rc5_decrypt((RC5Context *)context, in, out);
+ out[0] ^= tmp2[0];
+ out[1] ^= tmp2[1];
+ in += 2;
+ out += 2;
+ }
+
+ return TRUE;
+}
+
+#endif
--- /dev/null
+/*
+
+ rc5_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef RC5_INTERNAL_H
+#define RC5_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* RC5 definitions */
+#define w 32 /* word size, in bits */
+#define r 16 /* rounds */
+#define b 16 /* minimum key size in bytes */
+#define c 8 /* same for 128, 192 and 256 bits key */
+#define t 34 /* size of table S, t = 2 * (r + 1) */
+
+/* Cipher's context */
+typedef struct {
+ u32 out_key[t];
+} RC5Context;
+
+/* Prototypes */
+int rc5_set_key(RC5Context *ctx, char *key, int key_len);
+int rc5_encrypt(RC5Context *ctx, u32 *in, u32 *out);
+int rc5_decrypt(RC5Context *ctx, u32 *in, u32 *out);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm: */
+/* */
+/* RC6 by Ron Rivest and RSA Labs */
+/* */
+/* which is a candidate algorithm in the Advanced Encryption Standard */
+/* programme of the US National Institute of Standards and Technology. */
+/* */
+/* Copyright in this implementation is held by Dr B R Gladman but I */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions */
+/* that the originators of the algorithm place on its exploitation. */
+/* */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
+
+/* Timing data for RC6 (rc6.c)
+
+128 bit key:
+Key Setup: 1632 cycles
+Encrypt: 270 cycles = 94.8 mbits/sec
+Decrypt: 226 cycles = 113.3 mbits/sec
+Mean: 248 cycles = 103.2 mbits/sec
+
+192 bit key:
+Key Setup: 1885 cycles
+Encrypt: 267 cycles = 95.9 mbits/sec
+Decrypt: 235 cycles = 108.9 mbits/sec
+Mean: 251 cycles = 102.0 mbits/sec
+
+256 bit key:
+Key Setup: 1877 cycles
+Encrypt: 270 cycles = 94.8 mbits/sec
+Decrypt: 227 cycles = 112.8 mbits/sec
+Mean: 249 cycles = 103.0 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "rc6.h"
+
+/*
+ * SILC Crypto API for RC6
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(rc6)
+{
+ rc6_set_key((RC6Context *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc6)
+{
+ return 1;
+}
+
+/* Encrypts with the cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(rc6)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ rc6_encrypt((RC6Context *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ rc6_encrypt((RC6Context *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ tiv[0] = out[0 - 4];
+ tiv[1] = out[1 - 4];
+ tiv[2] = out[2 - 4];
+ tiv[3] = out[3 - 4];
+
+ return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(rc6)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4], tmp2[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ rc6_decrypt((RC6Context *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp2[0] = tmp[0];
+ tmp2[1] = tmp[1];
+ tmp2[2] = tmp[2];
+ tmp2[3] = tmp[3];
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ rc6_decrypt((RC6Context *)context, in, out);
+ out[0] ^= tmp2[0];
+ out[1] ^= tmp2[1];
+ out[2] ^= tmp2[2];
+ out[3] ^= tmp2[3];
+ in += 4;
+ out += 4;
+ }
+
+ tiv[0] = tmp[0];
+ tiv[1] = tmp[1];
+ tiv[2] = tmp[2];
+ tiv[3] = tmp[3];
+
+ return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(rc6)
+{
+ return sizeof(RC6Context);
+}
+
+
+#define f_rnd(i,a,b,c,d) \
+ u = rotl(d * (d + d + 1), 5); \
+ t = rotl(b * (b + b + 1), 5); \
+ a = rotl(a ^ t, u) + l_key[i]; \
+ c = rotl(c ^ u, t) + l_key[i + 1]
+
+#define i_rnd(i,a,b,c,d) \
+ u = rotl(d * (d + d + 1), 5); \
+ t = rotl(b * (b + b + 1), 5); \
+ c = rotr(c - l_key[i + 1], t) ^ u; \
+ a = rotr(a - l_key[i], u) ^ t
+
+/* initialise the key schedule from the user supplied key */
+
+u4byte *rc6_set_key(RC6Context *ctx,
+ const u4byte in_key[], const u4byte key_len)
+{
+ u4byte i, j, k, a, b, l[8], t;
+ u4byte *l_key = ctx->l_key;
+
+ l_key[0] = 0xb7e15163;
+
+ for(k = 1; k < 44; ++k)
+
+ l_key[k] = l_key[k - 1] + 0x9e3779b9;
+
+ for(k = 0; k < key_len / 32; ++k)
+
+ l[k] = in_key[k];
+
+ t = (key_len / 32) - 1; // t = (key_len / 32);
+
+ a = b = i = j = 0;
+
+ for(k = 0; k < 132; ++k)
+ { a = rotl(l_key[i] + a + b, 3); b += a;
+ b = rotl(l[j] + b, b);
+ l_key[i] = a; l[j] = b;
+ i = (i == 43 ? 0 : i + 1); // i = (i + 1) % 44;
+ j = (j == t ? 0 : j + 1); // j = (j + 1) % t;
+ }
+
+ return l_key;
+};
+
+/* encrypt a block of text */
+
+void rc6_encrypt(RC6Context *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte a,b,c,d,t,u;
+ u4byte *l_key = ctx->l_key;
+
+ a = in_blk[0]; b = in_blk[1] + l_key[0];
+ c = in_blk[2]; d = in_blk[3] + l_key[1];
+
+ f_rnd( 2,a,b,c,d); f_rnd( 4,b,c,d,a);
+ f_rnd( 6,c,d,a,b); f_rnd( 8,d,a,b,c);
+ f_rnd(10,a,b,c,d); f_rnd(12,b,c,d,a);
+ f_rnd(14,c,d,a,b); f_rnd(16,d,a,b,c);
+ f_rnd(18,a,b,c,d); f_rnd(20,b,c,d,a);
+ f_rnd(22,c,d,a,b); f_rnd(24,d,a,b,c);
+ f_rnd(26,a,b,c,d); f_rnd(28,b,c,d,a);
+ f_rnd(30,c,d,a,b); f_rnd(32,d,a,b,c);
+ f_rnd(34,a,b,c,d); f_rnd(36,b,c,d,a);
+ f_rnd(38,c,d,a,b); f_rnd(40,d,a,b,c);
+
+ out_blk[0] = a + l_key[42]; out_blk[1] = b;
+ out_blk[2] = c + l_key[43]; out_blk[3] = d;
+};
+
+/* decrypt a block of text */
+
+void rc6_decrypt(RC6Context *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte a,b,c,d,t,u;
+ u4byte *l_key = ctx->l_key;
+
+ d = in_blk[3]; c = in_blk[2] - l_key[43];
+ b = in_blk[1]; a = in_blk[0] - l_key[42];
+
+ i_rnd(40,d,a,b,c); i_rnd(38,c,d,a,b);
+ i_rnd(36,b,c,d,a); i_rnd(34,a,b,c,d);
+ i_rnd(32,d,a,b,c); i_rnd(30,c,d,a,b);
+ i_rnd(28,b,c,d,a); i_rnd(26,a,b,c,d);
+ i_rnd(24,d,a,b,c); i_rnd(22,c,d,a,b);
+ i_rnd(20,b,c,d,a); i_rnd(18,a,b,c,d);
+ i_rnd(16,d,a,b,c); i_rnd(14,c,d,a,b);
+ i_rnd(12,b,c,d,a); i_rnd(10,a,b,c,d);
+ i_rnd( 8,d,a,b,c); i_rnd( 6,c,d,a,b);
+ i_rnd( 4,b,c,d,a); i_rnd( 2,a,b,c,d);
+
+ out_blk[3] = d - l_key[1]; out_blk[2] = c;
+ out_blk[1] = b - l_key[0]; out_blk[0] = a;
+};
--- /dev/null
+/*
+
+ rc6.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef RC6_H
+#define RC6_H
+
+#include "rc6_internal.h"
+
+/*
+ * SILC Crypto API for RC6
+ */
+
+SILC_CIPHER_API_SET_KEY(rc6);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc6);
+SILC_CIPHER_API_CONTEXT_LEN(rc6);
+SILC_CIPHER_API_ENCRYPT_CBC(rc6);
+SILC_CIPHER_API_DECRYPT_CBC(rc6);
+
+#endif
--- /dev/null
+/*
+
+ rc6_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef RC6_INTERNAL_H
+#define RC6_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+ u4byte l_key[44];
+} RC6Context;
+
+/* Prototypes */
+u4byte *rc6_set_key(RC6Context *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void rc6_encrypt(RC6Context *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void rc6_decrypt(RC6Context *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm: */
+/* */
+/* RIJNDAEL by Joan Daemen and Vincent Rijmen */
+/* */
+/* which is a candidate algorithm in the Advanced Encryption Standard */
+/* programme of the US National Institute of Standards and Technology. */
+/* */
+/* Copyright in this implementation is held by Dr B R Gladman but I */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions */
+/* that the originators of the algorithm place on its exploitation. */
+/* */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
+
+/* Timing data for Rijndael (rijndael.c)
+
+Algorithm: rijndael (rijndael.c)
+
+128 bit key:
+Key Setup: 305/1389 cycles (encrypt/decrypt)
+Encrypt: 374 cycles = 68.4 mbits/sec
+Decrypt: 352 cycles = 72.7 mbits/sec
+Mean: 363 cycles = 70.5 mbits/sec
+
+192 bit key:
+Key Setup: 277/1595 cycles (encrypt/decrypt)
+Encrypt: 439 cycles = 58.3 mbits/sec
+Decrypt: 425 cycles = 60.2 mbits/sec
+Mean: 432 cycles = 59.3 mbits/sec
+
+256 bit key:
+Key Setup: 374/1960 cycles (encrypt/decrypt)
+Encrypt: 502 cycles = 51.0 mbits/sec
+Decrypt: 498 cycles = 51.4 mbits/sec
+Mean: 500 cycles = 51.2 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "rijndael.h"
+
+#define LARGE_TABLES
+
+u1byte pow_tab[256];
+u1byte log_tab[256];
+u1byte sbx_tab[256];
+u1byte isb_tab[256];
+u4byte rco_tab[ 10];
+u4byte ft_tab[4][256];
+u4byte it_tab[4][256];
+
+u4byte fl_tab[4][256];
+u4byte il_tab[4][256];
+
+u4byte tab_gen = 0;
+
+#define ff_mult(a,b) (a && b ? pow_tab[(log_tab[a] + log_tab[b]) % 255] : 0)
+
+#define f_rn(bo, bi, n, k) \
+ bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
+ ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
+ ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
+
+#define i_rn(bo, bi, n, k) \
+ bo[n] = it_tab[0][byte(bi[n],0)] ^ \
+ it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
+ it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
+
+#ifdef LARGE_TABLES
+
+#define ls_box(x) \
+ ( fl_tab[0][byte(x, 0)] ^ \
+ fl_tab[1][byte(x, 1)] ^ \
+ fl_tab[2][byte(x, 2)] ^ \
+ fl_tab[3][byte(x, 3)] )
+
+#define f_rl(bo, bi, n, k) \
+ bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
+ fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
+ fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
+
+#define i_rl(bo, bi, n, k) \
+ bo[n] = il_tab[0][byte(bi[n],0)] ^ \
+ il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
+ il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
+
+#else
+
+#define ls_box(x) \
+ ((u4byte)sbx_tab[byte(x, 0)] << 0) ^ \
+ ((u4byte)sbx_tab[byte(x, 1)] << 8) ^ \
+ ((u4byte)sbx_tab[byte(x, 2)] << 16) ^ \
+ ((u4byte)sbx_tab[byte(x, 3)] << 24)
+
+#define f_rl(bo, bi, n, k) \
+ bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \
+ rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
+ rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
+ rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
+
+#define i_rl(bo, bi, n, k) \
+ bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \
+ rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
+ rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
+ rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
+
+#endif
+
+void gen_tabs(void)
+{ u4byte i, t;
+ u1byte p, q;
+
+ /* log and power tables for GF(2**8) finite field with */
+ /* 0x11b as modular polynomial - the simplest prmitive */
+ /* root is 0x11, used here to generate the tables */
+
+ for(i = 0,p = 1; i < 256; ++i)
+ {
+ pow_tab[i] = (u1byte)p; log_tab[p] = (u1byte)i;
+
+ p = p ^ (p << 1) ^ (p & 0x80 ? 0x01b : 0);
+ }
+
+ log_tab[1] = 0; p = 1;
+
+ for(i = 0; i < 10; ++i)
+ {
+ rco_tab[i] = p;
+
+ p = (p << 1) ^ (p & 0x80 ? 0x1b : 0);
+ }
+
+ /* note that the affine byte transformation matrix in */
+ /* rijndael specification is in big endian format with */
+ /* bit 0 as the most significant bit. In the remainder */
+ /* of the specification the bits are numbered from the */
+ /* least significant end of a byte. */
+
+ for(i = 0; i < 256; ++i)
+ {
+ p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p;
+ q = (q >> 7) | (q << 1); p ^= q;
+ q = (q >> 7) | (q << 1); p ^= q;
+ q = (q >> 7) | (q << 1); p ^= q;
+ q = (q >> 7) | (q << 1); p ^= q ^ 0x63;
+ sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i;
+ }
+
+ for(i = 0; i < 256; ++i)
+ {
+ p = sbx_tab[i];
+
+#ifdef LARGE_TABLES
+
+ t = p; fl_tab[0][i] = t;
+ fl_tab[1][i] = rotl(t, 8);
+ fl_tab[2][i] = rotl(t, 16);
+ fl_tab[3][i] = rotl(t, 24);
+#endif
+ t = ((u4byte)ff_mult(2, p)) |
+ ((u4byte)p << 8) |
+ ((u4byte)p << 16) |
+ ((u4byte)ff_mult(3, p) << 24);
+
+ ft_tab[0][i] = t;
+ ft_tab[1][i] = rotl(t, 8);
+ ft_tab[2][i] = rotl(t, 16);
+ ft_tab[3][i] = rotl(t, 24);
+
+ p = isb_tab[i];
+
+#ifdef LARGE_TABLES
+
+ t = p; il_tab[0][i] = t;
+ il_tab[1][i] = rotl(t, 8);
+ il_tab[2][i] = rotl(t, 16);
+ il_tab[3][i] = rotl(t, 24);
+#endif
+ t = ((u4byte)ff_mult(14, p)) |
+ ((u4byte)ff_mult( 9, p) << 8) |
+ ((u4byte)ff_mult(13, p) << 16) |
+ ((u4byte)ff_mult(11, p) << 24);
+
+ it_tab[0][i] = t;
+ it_tab[1][i] = rotl(t, 8);
+ it_tab[2][i] = rotl(t, 16);
+ it_tab[3][i] = rotl(t, 24);
+ }
+
+ tab_gen = 1;
+};
+
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
+
+#define imix_col(y,x) \
+ u = star_x(x); \
+ v = star_x(u); \
+ w = star_x(v); \
+ t = w ^ (x); \
+ (y) = u ^ v ^ w; \
+ (y) ^= rotr(u ^ t, 8) ^ \
+ rotr(v ^ t, 16) ^ \
+ rotr(t,24)
+
+/* initialise the key schedule from the user supplied key */
+
+#define loop4(i) \
+{ \
+ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
+ t ^= e_key[4 * i]; e_key[4 * i + 4] = t; \
+ t ^= e_key[4 * i + 1]; e_key[4 * i + 5] = t; \
+ t ^= e_key[4 * i + 2]; e_key[4 * i + 6] = t; \
+ t ^= e_key[4 * i + 3]; e_key[4 * i + 7] = t; \
+}
+
+#define loop6(i) \
+{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
+ t ^= e_key[6 * i]; e_key[6 * i + 6] = t; \
+ t ^= e_key[6 * i + 1]; e_key[6 * i + 7] = t; \
+ t ^= e_key[6 * i + 2]; e_key[6 * i + 8] = t; \
+ t ^= e_key[6 * i + 3]; e_key[6 * i + 9] = t; \
+ t ^= e_key[6 * i + 4]; e_key[6 * i + 10] = t; \
+ t ^= e_key[6 * i + 5]; e_key[6 * i + 11] = t; \
+}
+
+#define loop8(i) \
+{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
+ t ^= e_key[8 * i]; e_key[8 * i + 8] = t; \
+ t ^= e_key[8 * i + 1]; e_key[8 * i + 9] = t; \
+ t ^= e_key[8 * i + 2]; e_key[8 * i + 10] = t; \
+ t ^= e_key[8 * i + 3]; e_key[8 * i + 11] = t; \
+ t = e_key[8 * i + 4] ^ ls_box(t); \
+ e_key[8 * i + 12] = t; \
+ t ^= e_key[8 * i + 5]; e_key[8 * i + 13] = t; \
+ t ^= e_key[8 * i + 6]; e_key[8 * i + 14] = t; \
+ t ^= e_key[8 * i + 7]; e_key[8 * i + 15] = t; \
+}
+
+u4byte *rijndael_set_key(RijndaelContext *ctx,
+ const u4byte in_key[], const u4byte key_len)
+{
+ u4byte i, t, u, v, w;
+ u4byte *e_key = ctx->e_key;
+ u4byte *d_key = ctx->d_key;
+ u4byte k_len;
+
+ if(!tab_gen)
+ gen_tabs();
+
+ k_len = ctx->k_len = (key_len + 31) / 32;
+
+ e_key[0] = in_key[0]; e_key[1] = in_key[1];
+ e_key[2] = in_key[2]; e_key[3] = in_key[3];
+
+ switch(k_len)
+ {
+ case 4: t = e_key[3];
+ for(i = 0; i < 10; ++i)
+ loop4(i);
+ break;
+
+ case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5];
+ for(i = 0; i < 8; ++i)
+ loop6(i);
+ break;
+
+ case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5];
+ e_key[6] = in_key[6]; t = e_key[7] = in_key[7];
+ for(i = 0; i < 7; ++i)
+ loop8(i);
+ break;
+ }
+
+ d_key[0] = e_key[0]; d_key[1] = e_key[1];
+ d_key[2] = e_key[2]; d_key[3] = e_key[3];
+
+ for(i = 4; i < 4 * k_len + 24; ++i)
+ {
+ imix_col(d_key[i], e_key[i]);
+ }
+
+ return e_key;
+};
+
+/* encrypt a block of text */
+
+#define f_nround(bo, bi, k) \
+ f_rn(bo, bi, 0, k); \
+ f_rn(bo, bi, 1, k); \
+ f_rn(bo, bi, 2, k); \
+ f_rn(bo, bi, 3, k); \
+ k += 4
+
+#define f_lround(bo, bi, k) \
+ f_rl(bo, bi, 0, k); \
+ f_rl(bo, bi, 1, k); \
+ f_rl(bo, bi, 2, k); \
+ f_rl(bo, bi, 3, k)
+
+void rijndael_encrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte b0[4], b1[4], *kp;
+ u4byte *e_key = ctx->e_key;
+ u4byte k_len = ctx->k_len;
+
+ b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1];
+ b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3];
+
+ kp = e_key + 4;
+
+ if(k_len > 6)
+ {
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ }
+
+ if(k_len > 4)
+ {
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ }
+
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_lround(b0, b1, kp);
+
+ out_blk[0] = b0[0]; out_blk[1] = b0[1];
+ out_blk[2] = b0[2]; out_blk[3] = b0[3];
+};
+
+/* decrypt a block of text */
+
+#define i_nround(bo, bi, k) \
+ i_rn(bo, bi, 0, k); \
+ i_rn(bo, bi, 1, k); \
+ i_rn(bo, bi, 2, k); \
+ i_rn(bo, bi, 3, k); \
+ k -= 4
+
+#define i_lround(bo, bi, k) \
+ i_rl(bo, bi, 0, k); \
+ i_rl(bo, bi, 1, k); \
+ i_rl(bo, bi, 2, k); \
+ i_rl(bo, bi, 3, k)
+
+void rijndael_decrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte b0[4], b1[4], *kp;
+ u4byte *e_key = ctx->e_key;
+ u4byte *d_key = ctx->d_key;
+ u4byte k_len = ctx->k_len;
+
+ b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25];
+ b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27];
+
+ kp = d_key + 4 * (k_len + 5);
+
+ if(k_len > 6)
+ {
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ }
+
+ if(k_len > 4)
+ {
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ }
+
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_lround(b0, b1, kp);
+
+ out_blk[0] = b0[0]; out_blk[1] = b0[1];
+ out_blk[2] = b0[2]; out_blk[3] = b0[3];
+};
--- /dev/null
+/*
+
+ rijndael.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef RIJNDAEL_H
+#define RIJNDAEL_H
+
+#include "rijndael_internal.h"
+
+/*
+ * SILC Crypto API for Rijndael
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(rijndael)
+{
+ rijndael_set_key((RijndaelContext *)context, (unsigned int *)key, keylen);
+ return TRUE;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rijndael)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+
+ return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(rijnadel)
+{
+ return sizeof(RijndaelContext);
+}
+
+/* Encrypts with the cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(rijndael)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ rijndael_encrypt((RijndaelContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ rijndael_encrypt((RijndaelContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(rijndael)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4], tmp2[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ rijndael_decrypt((RijndaelContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp2[0] = tmp[0];
+ tmp2[1] = tmp[1];
+ tmp2[2] = tmp[2];
+ tmp2[3] = tmp[3];
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ rijndael_decrypt((RijndaelContext *)context, in, out);
+ out[0] ^= tmp2[0];
+ out[1] ^= tmp2[1];
+ out[2] ^= tmp2[2];
+ out[3] ^= tmp2[3];
+ in += 4;
+ out += 4;
+ }
+
+ return TRUE;
+}
+
+#endif
--- /dev/null
+/*
+
+ rijndael_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef RIJNDAEL_INTERNAL_H
+#define RIJNDAEL_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+ u4byte e_key[60];
+ u4byte d_key[60];
+ u4byte k_len;
+} RijndaelContext;
+
+/* Prototypes */
+u4byte *rijndael_set_key(RijndaelContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void rijndael_encrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void rijndael_decrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/*
+ * rsa.c RSA Public and Private key generation functions,
+ * RSA encrypt and decrypt functions.
+ *
+ * Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ *
+ * Copyright (C) 1997 - 2000 Pekka Riikonen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Created: Sat Mar 1 13:26:45 1997 pekka
+ *
+ * RSA public key cryptographic algorithm used in this distribution is:
+ *
+ * Key generation:
+ * p, q primes
+ * p != q
+ * n = p * q modulus
+ *
+ * Public key exponent:
+ * e relatively prime to (p-1) * (q-1)
+ * Private key exponent:
+ * d = e ^ -1 mod ((p-1) * (q-1))
+ *
+ * Encryption:
+ * c = m ^ e mod n
+ * Decryption:
+ * m = c ^ d mod n
+ *
+ * This code is based on SSH's (Secure Shell), PGP's (Pretty Good Privacy)
+ * and RSAREF Toolkit's RSA source codes. They all were a big help for me.
+ *
+ * I also suggest reading Bruce Schneier's; Applied Cryptography, Second
+ * Edition, John Wiley & Sons, Inc. 1996. This book deals about RSA and
+ * everything else too about cryptography.
+ *
+ */
+
+#include "silcincludes.h"
+#include "rsa.h"
+
+/*
+ * SILC PKCS API for RSA
+ */
+
+/* Generates RSA key pair. */
+
+SILC_PKCS_API_INIT(rsa)
+{
+ unsigned int prime_bits = keylen / 2;
+ SilcInt p, q;
+
+ printf("Generating RSA Public and Private keys, might take a while...\n");
+
+ silc_mp_init(&p);
+ silc_mp_init(&q);
+
+ /* Find p and q */
+ retry_primes:
+ printf("Finding p: ");
+ silc_math_gen_prime(&p, prime_bits, TRUE);
+
+ printf("\nFinding q: ");
+ silc_math_gen_prime(&q, prime_bits, TRUE);
+
+ if ((silc_mp_cmp(&p, &q)) == 0) {
+ printf("\nFound equal primes, not good, retrying...\n");
+ goto retry_primes;
+ }
+
+ /* If p is smaller than q, switch them */
+ if ((silc_mp_cmp(&p, &q)) > 0) {
+ SilcInt hlp;
+ silc_mp_init(&hlp);
+
+ silc_mp_set(&hlp, &p);
+ silc_mp_set(&p, &q);
+ silc_mp_set(&q, &hlp);
+
+ silc_mp_clear(&hlp);
+ }
+
+ /* Generate the actual keys */
+ rsa_generate_keys((RsaKey *)context, keylen, &p, &q);
+
+ silc_mp_clear(&p);
+ silc_mp_clear(&q);
+
+ printf("\nKeys generated succesfully.\n");
+
+ return TRUE;
+}
+
+SILC_PKCS_API_CLEAR_KEYS(rsa)
+{
+ rsa_clear_keys((RsaKey *)context);
+}
+
+/* Returns SILC style encoded RSA public key. */
+
+SILC_PKCS_API_GET_PUBLIC_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ unsigned char *e, *n, *ret;
+ unsigned int e_len, n_len;
+ unsigned char tmp[2];
+
+ e_len = silc_mp_sizeinbase(&key->e, 16);
+ n_len = silc_mp_sizeinbase(&key->n, 16);
+ e = silc_calloc(e_len + 1, sizeof(unsigned char));
+ n = silc_calloc(n_len + 1, sizeof(unsigned char));
+ silc_mp_get_str(e, 16, &key->e);
+ silc_mp_get_str(n, 16, &key->n);
+
+ *ret_len = e_len + 2 + n_len + 2;
+ ret = silc_calloc(*ret_len, sizeof(unsigned char));
+
+ /* Put the length of the e. */
+ tmp[0] = e_len >> 8;
+ tmp[1] = e_len;
+ memcpy(ret, tmp, 2);
+
+ /* Put the e. */
+ memcpy(ret + 2, e, e_len);
+
+ /* Put the length of the n. */
+ tmp[0] = n_len >> 8;
+ tmp[1] = n_len;
+ memcpy(ret + 2 + e_len, tmp, 2);
+
+ /* Put the n. */
+ memcpy(ret + 2 + e_len + 2, n, n_len);
+
+ memset(e, 0, e_len);
+ memset(n, 0, n_len);
+ silc_free(e);
+ silc_free(n);
+
+ return ret;
+}
+
+/* Returns SILC style encoded RSA private key. Public key is always
+ returned in private key as well. Public keys are often derived
+ directly from private key. */
+
+SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ unsigned char *e, *n, *d, *ret;
+ unsigned int e_len, n_len, d_len;
+ unsigned char tmp[2];
+
+ e_len = silc_mp_sizeinbase(&key->e, 16);
+ n_len = silc_mp_sizeinbase(&key->n, 16);
+ d_len = silc_mp_sizeinbase(&key->d, 16);
+ e = silc_calloc(e_len + 1, sizeof(unsigned char));
+ n = silc_calloc(n_len + 1, sizeof(unsigned char));
+ d = silc_calloc(d_len + 1, sizeof(unsigned char));
+ silc_mp_get_str(e, 16, &key->e);
+ silc_mp_get_str(n, 16, &key->n);
+ silc_mp_get_str(d, 16, &key->d);
+
+ *ret_len = e_len + 2 + n_len + 2 + d_len + 2;
+ ret = silc_calloc(*ret_len, sizeof(unsigned char));
+
+ /* Put the length of the e. */
+ tmp[0] = e_len >> 8;
+ tmp[1] = e_len;
+ memcpy(ret, tmp, 2);
+
+ /* Put the e. */
+ memcpy(ret + 2, e, e_len);
+
+ /* Put the length of the n. */
+ tmp[0] = n_len >> 8;
+ tmp[1] = n_len;
+ memcpy(ret + 2 + e_len, tmp, 2);
+
+ /* Put the n. */
+ memcpy(ret + 2 + e_len + 2, n, n_len);
+
+ /* Put the length of the d. */
+ tmp[0] = d_len >> 8;
+ tmp[1] = d_len;
+ memcpy(ret + 2 + e_len + 2 + n_len, tmp, 2);
+
+ /* Put the n. */
+ memcpy(ret + 2 + e_len + 2 + n_len + 2, d, d_len);
+
+ memset(e, 0, e_len);
+ memset(n, 0, n_len);
+ memset(d, 0, d_len);
+ silc_free(e);
+ silc_free(n);
+ silc_free(d);
+
+ return ret;
+}
+
+/* Set public key */
+
+SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ unsigned char *e, *n, tmp[2];
+ unsigned int e_len, n_len;
+
+ silc_mp_init(&key->e);
+ silc_mp_init(&key->n);
+
+ memcpy(tmp, key_data, 2);
+ e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+ e = silc_calloc(e_len + 1, sizeof(unsigned char));
+ memcpy(e, key_data + 2, e_len);
+ silc_mp_set_str(&key->e, e, 16);
+
+ memcpy(tmp, key_data + 2 + e_len, 2);
+ n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+ n = silc_calloc(n_len + 1, sizeof(unsigned char));
+ memcpy(n, key_data + 2 + e_len + 2, n_len);
+ silc_mp_set_str(&key->n, n, 16);
+
+ memset(e, 0, e_len);
+ memset(n, 0, n_len);
+ silc_free(e);
+ silc_free(n);
+
+ return TRUE;
+}
+
+/* Set private key. This derives the public key from the private
+ key and sets the public key as well. Public key should not be set
+ already and should not be set after setting private key. */
+
+SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ unsigned char *e, *n, *d, tmp[2];
+ unsigned int e_len, n_len, d_len;
+
+ silc_mp_init(&key->e);
+ silc_mp_init(&key->n);
+ silc_mp_init(&key->d);
+
+ memcpy(tmp, key_data, 2);
+ e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+ e = silc_calloc(e_len + 1, sizeof(unsigned char));
+ memcpy(e, key_data + 2, e_len);
+ silc_mp_set_str(&key->e, e, 16);
+
+ memcpy(tmp, key_data + 2 + e_len, 2);
+ n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+ n = silc_calloc(n_len + 1, sizeof(unsigned char));
+ memcpy(n, key_data + 2 + e_len + 2, n_len);
+ silc_mp_set_str(&key->n, n, 16);
+
+ memcpy(tmp, key_data + 2 + e_len + 2 + n_len, 2);
+ d_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+ d = silc_calloc(d_len + 1, sizeof(unsigned char));
+ memcpy(d, key_data + 2 + e_len + 2 + n_len + 2, d_len);
+ silc_mp_set_str(&key->d, d, 16);
+
+ memset(e, 0, e_len);
+ memset(n, 0, n_len);
+ memset(d, 0, d_len);
+ silc_free(e);
+ silc_free(n);
+ silc_free(d);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_CONTEXT_LEN(rsa)
+{
+ return sizeof(RsaKey);
+}
+
+SILC_PKCS_API_DATA_CONTEXT_LEN(rsa)
+{
+ return sizeof(RsaDataContext);
+}
+
+SILC_PKCS_API_SET_ARG(rsa)
+{
+ RsaDataContext *data_ctx = (RsaDataContext *)data_context;
+
+ switch(argnum) {
+ case 1:
+ data_ctx->src = val;
+ return TRUE;
+ break;
+ case 2:
+ data_ctx->dst = val;
+ return TRUE;
+ break;
+ case 3:
+ data_ctx->exp = val;
+ return TRUE;
+ break;
+ case 4:
+ data_ctx->mod = val;
+ return TRUE;
+ break;
+ default:
+ return FALSE;
+ break;
+ }
+
+ return FALSE;
+}
+
+SILC_PKCS_API_ENCRYPT(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int i, tmplen;
+ SilcInt mp_tmp;
+ SilcInt mp_dst;
+
+ silc_mp_init_set_ui(&mp_tmp, 0);
+ silc_mp_init_set_ui(&mp_dst, 0);
+
+ /* Format the data into MP int */
+ for (i = 0; i < src_len; i++) {
+ silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+ silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
+ }
+
+ silc_mp_out_str(stderr, 16, &mp_tmp);
+
+ /* Encrypt */
+ rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->e, &key->n);
+
+ fprintf(stderr, "\n");
+ silc_mp_out_str(stderr, 16, &mp_dst);
+
+ tmplen = (1024 + 7) / 8;
+
+ /* Format the MP int back into data */
+ for (i = tmplen; i > 0; i--) {
+ dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
+ silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
+ }
+ *dst_len = tmplen;
+
+ silc_mp_clear(&mp_tmp);
+ silc_mp_clear(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_DECRYPT(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int i, tmplen;
+ SilcInt mp_tmp;
+ SilcInt mp_dst;
+
+ silc_mp_init_set_ui(&mp_tmp, 0);
+ silc_mp_init_set_ui(&mp_dst, 0);
+
+ /* Format the data into MP int */
+ for (i = 0; i < src_len; i++) {
+ silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+ silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
+ }
+
+ silc_mp_out_str(stderr, 16, &mp_tmp);
+
+ /* Decrypt */
+ rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->d, &key->n);
+
+ fprintf(stderr, "\n");
+ silc_mp_out_str(stderr, 16, &mp_dst);
+
+ tmplen = (1024 + 7) / 8;
+
+ /* Format the MP int back into data */
+ for (i = tmplen; i > 0; i--) {
+ dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
+ silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
+ }
+ *dst_len = tmplen;
+
+ silc_mp_clear(&mp_tmp);
+ silc_mp_clear(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_SIGN(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int i, tmplen;
+ SilcInt mp_tmp;
+ SilcInt mp_dst;
+
+ silc_mp_init_set_ui(&mp_tmp, 0);
+ silc_mp_init_set_ui(&mp_dst, 0);
+
+ /* Format the data into MP int */
+ for (i = 0; i < src_len; i++) {
+ silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+ silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
+ }
+
+ /* Sign */
+ rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->d, &key->n);
+
+ tmplen = (1024 + 7) / 8;
+
+ /* Format the MP int back into data */
+ for (i = tmplen; i > 0; i--) {
+ dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
+ silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
+ }
+ *dst_len = tmplen;
+
+ silc_mp_clear(&mp_tmp);
+ silc_mp_clear(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_VERIFY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int i, ret;
+ SilcInt mp_tmp, mp_tmp2;
+ SilcInt mp_dst;
+
+ silc_mp_init_set_ui(&mp_tmp, 0);
+ silc_mp_init_set_ui(&mp_tmp2, 0);
+ silc_mp_init_set_ui(&mp_dst, 0);
+
+ /* Format the signature into MP int */
+ for (i = 0; i < signature_len; i++) {
+ silc_mp_mul_2exp(&mp_tmp2, &mp_tmp2, 8);
+ silc_mp_add_ui(&mp_tmp2, &mp_tmp2, signature[i]);
+ }
+
+ /* Verify */
+ rsa_en_de_crypt(&mp_dst, &mp_tmp2, &key->e, &key->n);
+
+ /* Format the data into MP int */
+ for (i = 0; i < data_len; i++) {
+ silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+ silc_mp_add_ui(&mp_tmp, &mp_tmp, data[i]);
+ }
+
+ ret = TRUE;
+
+ /* Compare */
+ if ((silc_mp_cmp(&mp_tmp, &mp_dst)) != 0)
+ ret = FALSE;
+
+ silc_mp_clear(&mp_tmp);
+ silc_mp_clear(&mp_tmp2);
+ silc_mp_clear(&mp_dst);
+
+ return ret;
+}
+
+/* Generates RSA public and private keys. Primes p and q that are used
+ to compute the modulus n has to be generated before calling this. They
+ are then sent as argument for the function. */
+
+void rsa_generate_keys(RsaKey *key, unsigned int bits,
+ SilcInt *p, SilcInt *q)
+{
+ SilcInt phi, hlp;
+ SilcInt dq;
+ SilcInt pm1, qm1;
+
+ /* Initialize variables */
+ silc_mp_init(&key->p);
+ silc_mp_init(&key->q);
+ silc_mp_init(&key->n);
+ silc_mp_init(&key->e);
+ silc_mp_init(&key->d);
+ silc_mp_init(&phi);
+ silc_mp_init(&hlp);
+ silc_mp_init(&dq);
+ silc_mp_init(&pm1);
+ silc_mp_init(&qm1);
+
+ /* Set the primes */
+ silc_mp_set(&key->p, p);
+ silc_mp_set(&key->q, q);
+
+ /* Compute modulus, n = p * q */
+ silc_mp_mul(&key->n, &key->p, &key->q);
+
+ /* phi = (p - 1) * (q - 1) */
+ silc_mp_sub_ui(&pm1, &key->p, 1);
+ silc_mp_sub_ui(&qm1, &key->q, 1);
+ silc_mp_mul(&phi, &pm1, &qm1);
+
+ /* Set e, the public exponent. We try to use same public exponent
+ for all keys. Also, to make encryption faster we use small
+ number. */
+ silc_mp_set_ui(&key->e, 127);
+ retry_e:
+ /* See if e is relatively prime to phi. gcd == greates common divisor,
+ if gcd equals 1 they are relatively prime. */
+ silc_mp_gcd(&hlp, &key->e, &phi);
+ if((silc_mp_cmp_ui(&hlp, 1)) > 0) {
+ silc_mp_add_ui(&key->e, &key->e, 2);
+ goto retry_e;
+ }
+
+ /* Find d, the private exponent. First we do phi / 2, to get it a
+ bit smaller */
+ silc_mp_div_ui(&dq, &phi, 2);
+ silc_mp_modinv(&key->d, &key->e, &dq);
+
+ silc_mp_clear(&phi);
+ silc_mp_clear(&hlp);
+ silc_mp_clear(&dq);
+ silc_mp_clear(&pm1);
+ silc_mp_clear(&qm1);
+}
+
+/* Clears whole key structure. */
+
+void rsa_clear_keys(RsaKey *key)
+{
+ key->bits = 0;
+ silc_mp_clear(&key->p);
+ silc_mp_clear(&key->q);
+ silc_mp_clear(&key->n);
+ silc_mp_clear(&key->e);
+ silc_mp_clear(&key->d);
+}
+
+/* RSA encrypt/decrypt function. cm = ciphertext or plaintext,
+ mc = plaintext or ciphertext, expo = public or private exponent,
+ and modu = modulus.
+
+ Encrypt: c = m ^ e mod n,
+ Decrypt: m = c ^ d mod n
+*/
+
+void rsa_en_de_crypt(SilcInt *cm, SilcInt *mc,
+ SilcInt *expo, SilcInt *modu)
+{
+ silc_mp_powm(cm, mc, expo, modu);
+}
--- /dev/null
+/*
+
+ rsa.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef RSA_H
+#define RSA_H
+
+#include "rsa_internal.h"
+
+/* Data context for RSA */
+typedef struct {
+ SilcInt src;
+ SilcInt dst;
+ SilcInt exp;
+ SilcInt mod;
+} RsaDataContext;
+
+RsaDataContext *silc_rsa_data_context;
+
+/*
+ * SILC PKCS API for RSA
+ */
+
+SILC_PKCS_API_INIT(rsa);
+SILC_PKCS_API_CLEAR_KEYS(rsa);
+SILC_PKCS_API_GET_PUBLIC_KEY(rsa);
+SILC_PKCS_API_GET_PRIVATE_KEY(rsa);
+SILC_PKCS_API_SET_PUBLIC_KEY(rsa);
+SILC_PKCS_API_SET_PRIVATE_KEY(rsa);
+SILC_PKCS_API_CONTEXT_LEN(rsa);
+SILC_PKCS_API_DATA_CONTEXT_LEN(rsa);
+SILC_PKCS_API_SET_ARG(rsa);
+SILC_PKCS_API_ENCRYPT(rsa);
+SILC_PKCS_API_DECRYPT(rsa);
+SILC_PKCS_API_SIGN(rsa);
+SILC_PKCS_API_VERIFY(rsa);
+
+
+#endif
--- /dev/null
+/*
+
+ rsa_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef RSA_INTERNAL_H
+#define RSA_INTERNAL_H
+
+/* RSA Keys, includes both Private and Public key */
+typedef struct {
+ int bits; /* bits in key */
+ SilcInt p; /* prime p */
+ SilcInt q; /* prime q */
+ SilcInt n; /* modulus */
+ SilcInt e; /* public exponent */
+ SilcInt d; /* private exponent */
+} RsaKey;
+
+void rsa_generate_keys(RsaKey *key, unsigned int bits,
+ SilcInt *p, SilcInt *q);
+void rsa_clear_keys(RsaKey *key);
+void rsa_en_de_crypt(SilcInt *cm, SilcInt *mc,
+ SilcInt *expo, SilcInt *modu);
+
+#endif
--- /dev/null
+\r
+/* This is an independent implementation of the encryption algorithm: */\r
+/* */\r
+/* SAFER+ by Cylink */\r
+/* */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard */\r
+/* programme of the US National Institute of Standards and Technology. */\r
+/* */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions */\r
+/* that the originators of the algorithm place on its exploitation. */\r
+/* */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */\r
+\r
+/* Timing data for SAFER+ (safer.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 4278 cycles\r
+Encrypt: 1722 cycles = 14.9 mbits/sec\r
+Decrypt: 1709 cycles = 15.0 mbits/sec\r
+Mean: 1716 cycles = 14.9 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 7426 cycles\r
+Encrypt: 2555 cycles = 10.0 mbits/sec\r
+Decrypt: 2530 cycles = 10.1 mbits/sec\r
+Mean: 2543 cycles = 10.1 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 11313 cycles\r
+Encrypt: 3391 cycles = 7.5 mbits/sec\r
+Decrypt: 3338 cycles = 7.7 mbits/sec\r
+Mean: 3365 cycles = 7.6 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 3977 cycles\r
+Encrypt: 1751 cycles = 14.6 mbits/sec\r
+Decrypt: 1734 cycles = 14.8 mbits/sec\r
+Mean: 1743 cycles = 14.7 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 6490 cycles\r
+Encrypt: 2574 cycles = 9.9 mbits/sec\r
+Decrypt: 2549 cycles = 10.0 mbits/sec\r
+Mean: 2562 cycles = 10.0 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 9487 cycles\r
+Encrypt: 3412 cycles = 7.5 mbits/sec\r
+Decrypt: 3372 cycles = 7.6 mbits/sec\r
+Mean: 3392 cycles = 7.5 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "safer_internal.h"\r
+\r
+u1byte expf[256] =\r
+{ 1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63, \r
+ 8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247, \r
+ 64, 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177, \r
+ 255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, \r
+ 241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20, \r
+ 129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, \r
+ 4, 180, 133, 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, \r
+ 32, 155, 36, 78, 169, 152, 158, 171, 242, 96, 208, 108, 234, 250, 199, 217, \r
+ 0, 212, 31, 110, 67, 188, 236, 83, 137, 254, 122, 93, 73, 201, 50, 194, \r
+ 249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, 143, 10, \r
+ 193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80, \r
+ 2, 90, 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126, \r
+ 16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104, 54, 117, 125, 228, 237, \r
+ 128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175, 165, 229, 25, 97, \r
+ 253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, 200, 5, \r
+ 225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40 \r
+};\r
+\r
+u1byte logf[512] = \r
+{\r
+ 128, 0, 176, 9, 96, 239, 185, 253, 16, 18, 159, 228, 105, 186, 173, 248, \r
+ 192, 56, 194, 101, 79, 6, 148, 252, 25, 222, 106, 27, 93, 78, 168, 130, \r
+ 112, 237, 232, 236, 114, 179, 21, 195, 255, 171, 182, 71, 68, 1, 172, 37, \r
+ 201, 250, 142, 65, 26, 33, 203, 211, 13, 110, 254, 38, 88, 218, 50, 15, \r
+ 32, 169, 157, 132, 152, 5, 156, 187, 34, 140, 99, 231, 197, 225, 115, 198, \r
+ 175, 36, 91, 135, 102, 39, 247, 87, 244, 150, 177, 183, 92, 139, 213, 84, \r
+ 121, 223, 170, 246, 62, 163, 241, 17, 202, 245, 209, 23, 123, 147, 131, 188, \r
+ 189, 82, 30, 235, 174, 204, 214, 53, 8, 200, 138, 180, 226, 205, 191, 217, \r
+ 208, 80, 89, 63, 77, 98, 52, 10, 72, 136, 181, 86, 76, 46, 107, 158, \r
+ 210, 61, 60, 3, 19, 251, 151, 81, 117, 74, 145, 113, 35, 190, 118, 42, \r
+ 95, 249, 212, 85, 11, 220, 55, 49, 22, 116, 215, 119, 167, 230, 7, 219, \r
+ 164, 47, 70, 243, 97, 69, 103, 227, 12, 162, 59, 28, 133, 24, 4, 29, \r
+ 41, 160, 143, 178, 90, 216, 166, 126, 238, 141, 83, 75, 161, 154, 193, 14, \r
+ 122, 73, 165, 44, 129, 196, 199, 54, 43, 127, 67, 149, 51, 242, 108, 104, \r
+ 109, 240, 2, 40, 206, 221, 155, 234, 94, 153, 124, 20, 134, 207, 229, 66, \r
+ 184, 64, 120, 45, 58, 233, 100, 31, 146, 144, 125, 57, 111, 224, 137, 48,\r
+\r
+ 128, 0, 176, 9, 96, 239, 185, 253, 16, 18, 159, 228, 105, 186, 173, 248, \r
+ 192, 56, 194, 101, 79, 6, 148, 252, 25, 222, 106, 27, 93, 78, 168, 130, \r
+ 112, 237, 232, 236, 114, 179, 21, 195, 255, 171, 182, 71, 68, 1, 172, 37, \r
+ 201, 250, 142, 65, 26, 33, 203, 211, 13, 110, 254, 38, 88, 218, 50, 15, \r
+ 32, 169, 157, 132, 152, 5, 156, 187, 34, 140, 99, 231, 197, 225, 115, 198, \r
+ 175, 36, 91, 135, 102, 39, 247, 87, 244, 150, 177, 183, 92, 139, 213, 84, \r
+ 121, 223, 170, 246, 62, 163, 241, 17, 202, 245, 209, 23, 123, 147, 131, 188, \r
+ 189, 82, 30, 235, 174, 204, 214, 53, 8, 200, 138, 180, 226, 205, 191, 217, \r
+ 208, 80, 89, 63, 77, 98, 52, 10, 72, 136, 181, 86, 76, 46, 107, 158, \r
+ 210, 61, 60, 3, 19, 251, 151, 81, 117, 74, 145, 113, 35, 190, 118, 42, \r
+ 95, 249, 212, 85, 11, 220, 55, 49, 22, 116, 215, 119, 167, 230, 7, 219, \r
+ 164, 47, 70, 243, 97, 69, 103, 227, 12, 162, 59, 28, 133, 24, 4, 29, \r
+ 41, 160, 143, 178, 90, 216, 166, 126, 238, 141, 83, 75, 161, 154, 193, 14, \r
+ 122, 73, 165, 44, 129, 196, 199, 54, 43, 127, 67, 149, 51, 242, 108, 104, \r
+ 109, 240, 2, 40, 206, 221, 155, 234, 94, 153, 124, 20, 134, 207, 229, 66, \r
+ 184, 64, 120, 45, 58, 233, 100, 31, 146, 144, 125, 57, 111, 224, 137, 48\r
+};\r
+\r
+u4byte *safer_set_key(SaferContext *ctx,\r
+ const u4byte in_key[], const u4byte key_len)\r
+{ \r
+ u1byte by, lk[33];\r
+ u4byte i, j, k, l, m;\r
+ u1byte *l_key = ctx->l_key;\r
+\r
+ get_key(lk, key_len);\r
+\r
+ ctx->k_bytes = k_bytes = key_len / 8; lk[k_bytes] = 0;\r
+\r
+ for(i = 0; i < k_bytes; ++i)\r
+ {\r
+ lk[k_bytes] ^= lk[i]; l_key[i] = lk[i];\r
+ }\r
+\r
+ for(i = 0; i < k_bytes; ++i)\r
+ {\r
+ for(j = 0; j <= k_bytes; ++j)\r
+ {\r
+ by = lk[j]; lk[j] = by << 3 | by >> 5;\r
+ }\r
+\r
+ k = 17 * i + 35; l = 16 * i + 16; m = i + 1;\r
+\r
+ if(i < 16)\r
+ {\r
+ for(j = 0; j < 16; ++j)\r
+ {\r
+ l_key[l + j] = lk[m] + expf[expf[(k + j) & 255]];\r
+\r
+ m = (m == k_bytes ? 0 : m + 1);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for(j = 0; j < 16; ++j)\r
+ {\r
+ l_key[l + j] = lk[m] + expf[(k + j) & 255];\r
+\r
+ m = (m == k_bytes ? 0 : m + 1);\r
+ }\r
+ }\r
+ }\r
+ return (u4byte*)l_key;\r
+};\r
+\r
+void do_fr(u1byte x[16], u1byte *kp)\r
+{ u1byte t;\r
+\r
+ x[ 0] = expf[x[ 0] ^ kp[ 0]] + kp[16];\r
+ x[ 1] = logf[x[ 1] + kp[ 1]] ^ kp[17]; \r
+ x[ 2] = logf[x[ 2] + kp[ 2]] ^ kp[18]; \r
+ x[ 3] = expf[x[ 3] ^ kp[ 3]] + kp[19];\r
+\r
+ x[ 4] = expf[x[ 4] ^ kp[ 4]] + kp[20];\r
+ x[ 5] = logf[x[ 5] + kp[ 5]] ^ kp[21]; \r
+ x[ 6] = logf[x[ 6] + kp[ 6]] ^ kp[22]; \r
+ x[ 7] = expf[x[ 7] ^ kp[ 7]] + kp[23];\r
+ \r
+ x[ 8] = expf[x[ 8] ^ kp[ 8]] + kp[24];\r
+ x[ 9] = logf[x[ 9] + kp[ 9]] ^ kp[25]; \r
+ x[10] = logf[x[10] + kp[10]] ^ kp[26]; \r
+ x[11] = expf[x[11] ^ kp[11]] + kp[27];\r
+\r
+ x[12] = expf[x[12] ^ kp[12]] + kp[28];\r
+ x[13] = logf[x[13] + kp[13]] ^ kp[29]; \r
+ x[14] = logf[x[14] + kp[14]] ^ kp[30]; \r
+ x[15] = expf[x[15] ^ kp[15]] + kp[31];\r
+\r
+ x[ 1] += x[ 0]; x[ 0] += x[ 1];\r
+ x[ 3] += x[ 2]; x[ 2] += x[ 3];\r
+ x[ 5] += x[ 4]; x[ 4] += x[ 5];\r
+ x[ 7] += x[ 6]; x[ 6] += x[ 7];\r
+ x[ 9] += x[ 8]; x[ 8] += x[ 9];\r
+ x[11] += x[10]; x[10] += x[11];\r
+ x[13] += x[12]; x[12] += x[13];\r
+ x[15] += x[14]; x[14] += x[15];\r
+\r
+ x[ 7] += x[ 0]; x[ 0] += x[ 7];\r
+ x[ 1] += x[ 2]; x[ 2] += x[ 1];\r
+ x[ 3] += x[ 4]; x[ 4] += x[ 3];\r
+ x[ 5] += x[ 6]; x[ 6] += x[ 5];\r
+ x[11] += x[ 8]; x[ 8] += x[11];\r
+ x[ 9] += x[10]; x[10] += x[ 9];\r
+ x[15] += x[12]; x[12] += x[15];\r
+ x[13] += x[14]; x[14] += x[13];\r
+\r
+ x[ 3] += x[ 0]; x[ 0] += x[ 3];\r
+ x[15] += x[ 2]; x[ 2] += x[15];\r
+ x[ 7] += x[ 4]; x[ 4] += x[ 7];\r
+ x[ 1] += x[ 6]; x[ 6] += x[ 1];\r
+ x[ 5] += x[ 8]; x[ 8] += x[ 5];\r
+ x[13] += x[10]; x[10] += x[13];\r
+ x[11] += x[12]; x[12] += x[11];\r
+ x[ 9] += x[14]; x[14] += x[ 9];\r
+\r
+ x[13] += x[ 0]; x[ 0] += x[13];\r
+ x[ 5] += x[ 2]; x[ 2] += x[ 5];\r
+ x[ 9] += x[ 4]; x[ 4] += x[ 9];\r
+ x[11] += x[ 6]; x[ 6] += x[11];\r
+ x[15] += x[ 8]; x[ 8] += x[15];\r
+ x[ 1] += x[10]; x[10] += x[ 1];\r
+ x[ 3] += x[12]; x[12] += x[ 3];\r
+ x[ 7] += x[14]; x[14] += x[ 7];\r
+\r
+ t = x[0]; x[0] = x[14]; x[14] = x[12]; x[12] = x[10]; x[10] = x[2]; \r
+ x[2] = x[8]; x[8] = x[4]; x[4] = t;\r
+\r
+ t = x[1]; x[1] = x[7]; x[7] = x[11]; x[11] = x[5]; x[5] = x[13]; x[13] = t; \r
+ \r
+ t = x[15]; x[15] = x[3]; x[3] = t;\r
+};\r
+\r
+void do_ir(u1byte x[16], u1byte *kp)\r
+{ u1byte t;\r
+\r
+ t = x[3]; x[3] = x[15]; x[15] = t; \r
+\r
+ t = x[13]; x[13] = x[5]; x[5] = x[11]; x[11] = x[7]; x[7] = x[1]; x[1] = t; \r
+\r
+ t = x[4]; x[4] = x[8]; x[8] = x[2]; x[2] = x[10]; \r
+ x[10] = x[12]; x[12] = x[14]; x[14] = x[0]; x[0] = t; \r
+\r
+ x[14] -= x[ 7]; x[ 7] -= x[14]; \r
+ x[12] -= x[ 3]; x[ 3] -= x[12];\r
+ x[10] -= x[ 1]; x[ 1] -= x[10];\r
+ x[ 8] -= x[15]; x[15] -= x[ 8];\r
+ x[ 6] -= x[11]; x[11] -= x[ 6]; \r
+ x[ 4] -= x[ 9]; x[ 9] -= x[ 4];\r
+ x[ 2] -= x[ 5]; x[ 5] -= x[ 2]; \r
+ x[ 0] -= x[13]; x[13] -= x[ 0]; \r
+\r
+ x[14] -= x[ 9]; x[ 9] -= x[14]; \r
+ x[12] -= x[11]; x[11] -= x[12]; \r
+ x[10] -= x[13]; x[13] -= x[10]; \r
+ x[ 8] -= x[ 5]; x[ 5] -= x[ 8]; \r
+ x[ 6] -= x[ 1]; x[ 1] -= x[ 6]; \r
+ x[ 4] -= x[ 7]; x[ 7] -= x[ 4]; \r
+ x[ 2] -= x[15]; x[15] -= x[ 2]; \r
+ x[ 0] -= x[ 3]; x[ 3] -= x[ 0]; \r
+\r
+ x[14] -= x[13]; x[13] -= x[14]; \r
+ x[12] -= x[15]; x[15] -= x[12]; \r
+ x[10] -= x[ 9]; x[ 9] -= x[10]; \r
+ x[ 8] -= x[11]; x[11] -= x[ 8]; \r
+ x[ 6] -= x[ 5]; x[ 5] -= x[ 6]; \r
+ x[ 4] -= x[ 3]; x[ 3] -= x[ 4]; \r
+ x[ 2] -= x[ 1]; x[ 1] -= x[ 2]; \r
+ x[ 0] -= x[ 7]; x[ 7] -= x[ 0]; \r
+\r
+ x[14] -= x[15]; x[15] -= x[14]; \r
+ x[12] -= x[13]; x[13] -= x[12];\r
+ x[10] -= x[11]; x[11] -= x[10]; \r
+ x[ 8] -= x[ 9]; x[ 9] -= x[ 8]; \r
+ x[ 6] -= x[ 7]; x[ 7] -= x[ 6];\r
+ x[ 4] -= x[ 5]; x[ 5] -= x[ 4]; \r
+ x[ 2] -= x[ 3]; x[ 3] -= x[ 2]; \r
+ x[ 0] -= x[ 1]; x[ 1] -= x[ 0]; \r
+ \r
+ x[ 0] = logf[x[ 0] - kp[16] + 256] ^ kp[ 0];\r
+ x[ 1] = expf[x[ 1] ^ kp[17]] - kp[ 1];\r
+ x[ 2] = expf[x[ 2] ^ kp[18]] - kp[ 2];\r
+ x[ 3] = logf[x[ 3] - kp[19] + 256] ^ kp[ 3];\r
+\r
+ x[ 4] = logf[x[ 4] - kp[20] + 256] ^ kp[ 4];\r
+ x[ 5] = expf[x[ 5] ^ kp[21]] - kp[ 5];\r
+ x[ 6] = expf[x[ 6] ^ kp[22]] - kp[ 6];\r
+ x[ 7] = logf[x[ 7] - kp[23] + 256] ^ kp[ 7];\r
+\r
+ x[ 8] = logf[x[ 8] - kp[24] + 256] ^ kp[ 8];\r
+ x[ 9] = expf[x[ 9] ^ kp[25]] - kp[ 9];\r
+ x[10] = expf[x[10] ^ kp[26]] - kp[10];\r
+ x[11] = logf[x[11] - kp[27] + 256] ^ kp[11];\r
+\r
+ x[12] = logf[x[12] - kp[28] + 256] ^ kp[12];\r
+ x[13] = expf[x[13] ^ kp[29]] - kp[13];\r
+ x[14] = expf[x[14] ^ kp[30]] - kp[14];\r
+ x[15] = logf[x[15] - kp[31] + 256] ^ kp[15];\r
+};\r
+\r
+void safer_encrypt(SaferContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u1byte blk[16], *kp;\r
+ u1byte *l_key = ctx->l_key;\r
+ u4byte k_bytes = ctx->k_bytes;\r
+\r
+ get_block(blk);\r
+\r
+ do_fr(blk, l_key); do_fr(blk, l_key + 32); \r
+ do_fr(blk, l_key + 64); do_fr(blk, l_key + 96);\r
+ do_fr(blk, l_key + 128); do_fr(blk, l_key + 160);\r
+ do_fr(blk, l_key + 192); do_fr(blk, l_key + 224);\r
+ \r
+ if(k_bytes > 16)\r
+ {\r
+ do_fr(blk, l_key + 256); do_fr(blk, l_key + 288); \r
+ do_fr(blk, l_key + 320); do_fr(blk, l_key + 352);\r
+ }\r
+\r
+ if(k_bytes > 24)\r
+ {\r
+ do_fr(blk, l_key + 384); do_fr(blk, l_key + 416); \r
+ do_fr(blk, l_key + 448); do_fr(blk, l_key + 480);\r
+ }\r
+\r
+ kp = l_key + 16 * k_bytes;\r
+\r
+ blk[ 0] ^= kp[ 0]; blk[ 1] += kp[ 1];\r
+ blk[ 2] += kp[ 2]; blk[ 3] ^= kp[ 3]; \r
+ blk[ 4] ^= kp[ 4]; blk[ 5] += kp[ 5];\r
+ blk[ 6] += kp[ 6]; blk[ 7] ^= kp[ 7]; \r
+ blk[ 8] ^= kp[ 8]; blk[ 9] += kp[ 9];\r
+ blk[10] += kp[10]; blk[11] ^= kp[11]; \r
+ blk[12] ^= kp[12]; blk[13] += kp[13];\r
+ blk[14] += kp[14]; blk[15] ^= kp[15]; \r
+\r
+ put_block(blk);\r
+};\r
+\r
+void safer_decrypt(SaferContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u1byte blk[16], *kp;\r
+ u1byte *l_key = ctx->l_key;\r
+ u4byte k_bytes = ctx->k_bytes;\r
+\r
+ get_block(blk);\r
+\r
+ kp = l_key + 16 * k_bytes;\r
+\r
+ blk[ 0] ^= kp[ 0]; blk[ 1] -= kp[ 1];\r
+ blk[ 2] -= kp[ 2]; blk[ 3] ^= kp[ 3];\r
+ blk[ 4] ^= kp[ 4]; blk[ 5] -= kp[ 5];\r
+ blk[ 6] -= kp[ 6]; blk[ 7] ^= kp[ 7];\r
+ blk[ 8] ^= kp[ 8]; blk[ 9] -= kp[ 9];\r
+ blk[10] -= kp[10]; blk[11] ^= kp[11];\r
+ blk[12] ^= kp[12]; blk[13] -= kp[13];\r
+ blk[14] -= kp[14]; blk[15] ^= kp[15];\r
+\r
+ if(k_bytes > 24)\r
+ {\r
+ do_ir(blk, l_key + 480); do_ir(blk, l_key + 448); \r
+ do_ir(blk, l_key + 416); do_ir(blk, l_key + 384);\r
+ }\r
+\r
+ if(k_bytes > 16)\r
+ {\r
+ do_ir(blk, l_key + 352); do_ir(blk, l_key + 320); \r
+ do_ir(blk, l_key + 288); do_ir(blk, l_key + 256);\r
+ }\r
+\r
+ do_ir(blk, l_key + 224); do_ir(blk, l_key + 192); \r
+ do_ir(blk, l_key + 160); do_ir(blk, l_key + 128);\r
+ do_ir(blk, l_key + 96); do_ir(blk, l_key + 64); \r
+ do_ir(blk, l_key + 32); do_ir(blk, l_key);\r
+\r
+ put_block(blk);\r
+};\r
--- /dev/null
+/*
+
+ safer.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef SAFER_H
+#define SAFER_H
+
+#include "safer_internal.h"
+
+/*
+ * SILC Crypto API for Safer
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_safer_init(void *context,
+ const unsigned char *key,
+ size_t keylen)
+{
+ safer_set_key((SaferContext *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+inline int silc_safer_set_string_as_key(void *context,
+ const unsigned char *string,
+ size_t keylen)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+
+ return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_safer_context_len()
+{
+ return sizeof(SaferContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_safer_encrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ safer_encrypt((SaferContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ safer_encrypt((SaferContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_safer_decrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ safer_decrypt((SaferContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ safer_decrypt((SaferContext *)context, in, out);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+
+ safer_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SAFER_INTERNAL_H
+#define SAFER_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+ u1byte l_key[33 * 16];
+ u4byte k_bytes;
+} SaferContext;
+
+/* Prototypes */
+u4byte *safer_set_key(SaferContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void safer_encrypt(SaferContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void safer_decrypt(SaferContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/* Modified for SILC. -Pekka */x\r
+\r
+/* This is an independent implementation of the encryption algorithm: */\r
+/* */\r
+/* Serpent by Ross Anderson, Eli Biham and Lars Knudsen */\r
+/* */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard */\r
+/* programme of the US National Institute of Standards and Technology. */\r
+/* */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions */\r
+/* that the originators of the algorithm place on its exploitation. */\r
+/* */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */\r
+\r
+/* Timing data for Serpent (serpent.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 2402 cycles\r
+Encrypt: 952 cycles = 26.9 mbits/sec\r
+Decrypt: 914 cycles = 28.0 mbits/sec\r
+Mean: 933 cycles = 27.4 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 2449 cycles\r
+Encrypt: 952 cycles = 26.9 mbits/sec\r
+Decrypt: 914 cycles = 28.0 mbits/sec\r
+Mean: 933 cycles = 27.4 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 2349 cycles\r
+Encrypt: 952 cycles = 26.9 mbits/sec\r
+Decrypt: 914 cycles = 28.0 mbits/sec\r
+Mean: 933 cycles = 27.4 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup: 2415 cycles\r
+Encrypt: 985 cycles = 26.0 mbits/sec\r
+Decrypt: 954 cycles = 26.8 mbits/sec\r
+Mean: 970 cycles = 26.4 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup: 2438 cycles\r
+Encrypt: 985 cycles = 26.0 mbits/sec\r
+Decrypt: 954 cycles = 26.8 mbits/sec\r
+Mean: 970 cycles = 26.4 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup: 2463 cycles\r
+Encrypt: 985 cycles = 26.0 mbits/sec\r
+Decrypt: 954 cycles = 26.8 mbits/sec\r
+Mean: 970 cycles = 26.4 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "serpent_internal.h"\r
+\r
+/* Partially optimised Serpent S Box boolean functions derived */\r
+/* using a recursive descent analyser but without a full search */\r
+/* of all subtrees. This set of S boxes is the result of work */\r
+/* by Sam Simpson and Brian Gladman using the spare time on a */\r
+/* cluster of high capacity servers to search for S boxes with */\r
+/* this customised search engine. */\r
+/* */\r
+/* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */\r
+/* and Sam Simpson (s.simpson@mia.co.uk) */ \r
+/* 17th December 1998 */\r
+/* */\r
+/* We hereby give permission for information in this file to be */\r
+/* used freely subject only to acknowledgement of its origin */\r
+\r
+/* 15 terms */\r
+\r
+#define sb0(a,b,c,d,e,f,g,h) \\r
+ t1 = a ^ d; \\r
+ t2 = a & d; \\r
+ t3 = c ^ t1; \\r
+ t6 = b & t1; \\r
+ t4 = b ^ t3; \\r
+ t10 = ~t3; \\r
+ h = t2 ^ t4; \\r
+ t7 = a ^ t6; \\r
+ t14 = ~t7; \\r
+ t8 = c | t7; \\r
+ t11 = t3 ^ t7; \\r
+ g = t4 ^ t8; \\r
+ t12 = h & t11; \\r
+ f = t10 ^ t12; \\r
+ e = t12 ^ t14\r
+\r
+/* 15 terms */\r
+\r
+#define ib0(a,b,c,d,e,f,g,h) \\r
+ t1 = ~a; \\r
+ t2 = a ^ b; \\r
+ t3 = t1 | t2; \\r
+ t4 = d ^ t3; \\r
+ t7 = d & t2; \\r
+ t5 = c ^ t4; \\r
+ t8 = t1 ^ t7; \\r
+ g = t2 ^ t5; \\r
+ t11 = a & t4; \\r
+ t9 = g & t8; \\r
+ t14 = t5 ^ t8; \\r
+ f = t4 ^ t9; \\r
+ t12 = t5 | f; \\r
+ h = t11 ^ t12; \\r
+ e = h ^ t14\r
+\r
+/* 14 terms! */\r
+\r
+#define sb1(a,b,c,d,e,f,g,h) \\r
+ t1 = ~a; \\r
+ t2 = b ^ t1; \\r
+ t3 = a | t2; \\r
+ t4 = d | t2; \\r
+ t5 = c ^ t3; \\r
+ g = d ^ t5; \\r
+ t7 = b ^ t4; \\r
+ t8 = t2 ^ g; \\r
+ t9 = t5 & t7; \\r
+ h = t8 ^ t9; \\r
+ t11 = t5 ^ t7; \\r
+ f = h ^ t11; \\r
+ t13 = t8 & t11; \\r
+ e = t5 ^ t13\r
+\r
+/* 17 terms */\r
+\r
+#define ib1(a,b,c,d,e,f,g,h) \\r
+ t1 = a ^ d; \\r
+ t2 = a & b; \\r
+ t3 = b ^ c; \\r
+ t4 = a ^ t3; \\r
+ t5 = b | d; \\r
+ t7 = c | t1; \\r
+ h = t4 ^ t5; \\r
+ t8 = b ^ t7; \\r
+ t11 = ~t2; \\r
+ t9 = t4 & t8; \\r
+ f = t1 ^ t9; \\r
+ t13 = t9 ^ t11; \\r
+ t12 = h & f; \\r
+ g = t12 ^ t13; \\r
+ t15 = a & d; \\r
+ t16 = c ^ t13; \\r
+ e = t15 ^ t16\r
+\r
+/* 16 terms */\r
+\r
+#define sb2(a,b,c,d,e,f,g,h) \\r
+ t1 = ~a; \\r
+ t2 = b ^ d; \\r
+ t3 = c & t1; \\r
+ t13 = d | t1; \\r
+ e = t2 ^ t3; \\r
+ t5 = c ^ t1; \\r
+ t6 = c ^ e; \\r
+ t7 = b & t6; \\r
+ t10 = e | t5; \\r
+ h = t5 ^ t7; \\r
+ t9 = d | t7; \\r
+ t11 = t9 & t10; \\r
+ t14 = t2 ^ h; \\r
+ g = a ^ t11; \\r
+ t15 = g ^ t13; \\r
+ f = t14 ^ t15\r
+\r
+/* 16 terms */\r
+\r
+#define ib2(a,b,c,d,e,f,g,h) \\r
+ t1 = b ^ d; \\r
+ t2 = ~t1; \\r
+ t3 = a ^ c; \\r
+ t4 = c ^ t1; \\r
+ t7 = a | t2; \\r
+ t5 = b & t4; \\r
+ t8 = d ^ t7; \\r
+ t11 = ~t4; \\r
+ e = t3 ^ t5; \\r
+ t9 = t3 | t8; \\r
+ t14 = d & t11; \\r
+ h = t1 ^ t9; \\r
+ t12 = e | h; \\r
+ f = t11 ^ t12; \\r
+ t15 = t3 ^ t12; \\r
+ g = t14 ^ t15\r
+\r
+/* 17 terms */\r
+\r
+#define sb3(a,b,c,d,e,f,g,h) \\r
+ t1 = a ^ c; \\r
+ t2 = d ^ t1; \\r
+ t3 = a & t2; \\r
+ t4 = d ^ t3; \\r
+ t5 = b & t4; \\r
+ g = t2 ^ t5; \\r
+ t7 = a | g; \\r
+ t8 = b | d; \\r
+ t11 = a | d; \\r
+ t9 = t4 & t7; \\r
+ f = t8 ^ t9; \\r
+ t12 = b ^ t11; \\r
+ t13 = g ^ t9; \\r
+ t15 = t3 ^ t8; \\r
+ h = t12 ^ t13; \\r
+ t16 = c & t15; \\r
+ e = t12 ^ t16\r
+\r
+/* 16 term solution that performs less well than 17 term one\r
+ in my environment (PPro/PII) \r
+\r
+#define sb3(a,b,c,d,e,f,g,h) \\r
+ t1 = a ^ b; \\r
+ t2 = a & c; \\r
+ t3 = a | d; \\r
+ t4 = c ^ d; \\r
+ t5 = t1 & t3; \\r
+ t6 = t2 | t5; \\r
+ g = t4 ^ t6; \\r
+ t8 = b ^ t3; \\r
+ t9 = t6 ^ t8; \\r
+ t10 = t4 & t9; \\r
+ e = t1 ^ t10; \\r
+ t12 = g & e; \\r
+ f = t9 ^ t12; \\r
+ t14 = b | d; \\r
+ t15 = t4 ^ t12; \\r
+ h = t14 ^ t15\r
+*/\r
+\r
+/* 17 terms */\r
+\r
+#define ib3(a,b,c,d,e,f,g,h) \\r
+ t1 = b ^ c; \\r
+ t2 = b | c; \\r
+ t3 = a ^ c; \\r
+ t7 = a ^ d; \\r
+ t4 = t2 ^ t3; \\r
+ t5 = d | t4; \\r
+ t9 = t2 ^ t7; \\r
+ e = t1 ^ t5; \\r
+ t8 = t1 | t5; \\r
+ t11 = a & t4; \\r
+ g = t8 ^ t9; \\r
+ t12 = e | t9; \\r
+ f = t11 ^ t12; \\r
+ t14 = a & g; \\r
+ t15 = t2 ^ t14; \\r
+ t16 = e & t15; \\r
+ h = t4 ^ t16\r
+\r
+/* 15 terms */\r
+\r
+#define sb4(a,b,c,d,e,f,g,h) \\r
+ t1 = a ^ d; \\r
+ t2 = d & t1; \\r
+ t3 = c ^ t2; \\r
+ t4 = b | t3; \\r
+ h = t1 ^ t4; \\r
+ t6 = ~b; \\r
+ t7 = t1 | t6; \\r
+ e = t3 ^ t7; \\r
+ t9 = a & e; \\r
+ t10 = t1 ^ t6; \\r
+ t11 = t4 & t10; \\r
+ g = t9 ^ t11; \\r
+ t13 = a ^ t3; \\r
+ t14 = t10 & g; \\r
+ f = t13 ^ t14\r
+\r
+/* 17 terms */\r
+\r
+#define ib4(a,b,c,d,e,f,g,h) \\r
+ t1 = c ^ d; \\r
+ t2 = c | d; \\r
+ t3 = b ^ t2; \\r
+ t4 = a & t3; \\r
+ f = t1 ^ t4; \\r
+ t6 = a ^ d; \\r
+ t7 = b | d; \\r
+ t8 = t6 & t7; \\r
+ h = t3 ^ t8; \\r
+ t10 = ~a; \\r
+ t11 = c ^ h; \\r
+ t12 = t10 | t11;\\r
+ e = t3 ^ t12; \\r
+ t14 = c | t4; \\r
+ t15 = t7 ^ t14; \\r
+ t16 = h | t10; \\r
+ g = t15 ^ t16\r
+\r
+/* 16 terms */\r
+\r
+#define sb5(a,b,c,d,e,f,g,h) \\r
+ t1 = ~a; \\r
+ t2 = a ^ b; \\r
+ t3 = a ^ d; \\r
+ t4 = c ^ t1; \\r
+ t5 = t2 | t3; \\r
+ e = t4 ^ t5; \\r
+ t7 = d & e; \\r
+ t8 = t2 ^ e; \\r
+ t10 = t1 | e; \\r
+ f = t7 ^ t8; \\r
+ t11 = t2 | t7; \\r
+ t12 = t3 ^ t10; \\r
+ t14 = b ^ t7; \\r
+ g = t11 ^ t12; \\r
+ t15 = f & t12; \\r
+ h = t14 ^ t15\r
+\r
+/* 16 terms */\r
+\r
+#define ib5(a,b,c,d,e,f,g,h) \\r
+ t1 = ~c; \\r
+ t2 = b & t1; \\r
+ t3 = d ^ t2; \\r
+ t4 = a & t3; \\r
+ t5 = b ^ t1; \\r
+ h = t4 ^ t5; \\r
+ t7 = b | h; \\r
+ t8 = a & t7; \\r
+ f = t3 ^ t8; \\r
+ t10 = a | d; \\r
+ t11 = t1 ^ t7; \\r
+ e = t10 ^ t11; \\r
+ t13 = a ^ c; \\r
+ t14 = b & t10; \\r
+ t15 = t4 | t13; \\r
+ g = t14 ^ t15\r
+\r
+/* 15 terms */\r
+\r
+#define sb6(a,b,c,d,e,f,g,h) \\r
+ t1 = ~a; \\r
+ t2 = a ^ d; \\r
+ t3 = b ^ t2; \\r
+ t4 = t1 | t2; \\r
+ t5 = c ^ t4; \\r
+ f = b ^ t5; \\r
+ t13 = ~t5; \\r
+ t7 = t2 | f; \\r
+ t8 = d ^ t7; \\r
+ t9 = t5 & t8; \\r
+ g = t3 ^ t9; \\r
+ t11 = t5 ^ t8; \\r
+ e = g ^ t11; \\r
+ t14 = t3 & t11; \\r
+ h = t13 ^ t14\r
+\r
+/* 15 terms */\r
+\r
+#define ib6(a,b,c,d,e,f,g,h) \\r
+ t1 = ~a; \\r
+ t2 = a ^ b; \\r
+ t3 = c ^ t2; \\r
+ t4 = c | t1; \\r
+ t5 = d ^ t4; \\r
+ t13 = d & t1; \\r
+ f = t3 ^ t5; \\r
+ t7 = t3 & t5; \\r
+ t8 = t2 ^ t7; \\r
+ t9 = b | t8; \\r
+ h = t5 ^ t9; \\r
+ t11 = b | h; \\r
+ e = t8 ^ t11; \\r
+ t14 = t3 ^ t11; \\r
+ g = t13 ^ t14\r
+\r
+/* 17 terms */\r
+\r
+#define sb7(a,b,c,d,e,f,g,h) \\r
+ t1 = ~c; \\r
+ t2 = b ^ c; \\r
+ t3 = b | t1; \\r
+ t4 = d ^ t3; \\r
+ t5 = a & t4; \\r
+ t7 = a ^ d; \\r
+ h = t2 ^ t5; \\r
+ t8 = b ^ t5; \\r
+ t9 = t2 | t8; \\r
+ t11 = d & t3; \\r
+ f = t7 ^ t9; \\r
+ t12 = t5 ^ f; \\r
+ t15 = t1 | t4; \\r
+ t13 = h & t12; \\r
+ g = t11 ^ t13; \\r
+ t16 = t12 ^ g; \\r
+ e = t15 ^ t16\r
+\r
+/* 17 terms */\r
+\r
+#define ib7(a,b,c,d,e,f,g,h) \\r
+ t1 = a & b; \\r
+ t2 = a | b; \\r
+ t3 = c | t1; \\r
+ t4 = d & t2; \\r
+ h = t3 ^ t4; \\r
+ t6 = ~d; \\r
+ t7 = b ^ t4; \\r
+ t8 = h ^ t6; \\r
+ t11 = c ^ t7; \\r
+ t9 = t7 | t8; \\r
+ f = a ^ t9; \\r
+ t12 = d | f; \\r
+ e = t11 ^ t12; \\r
+ t14 = a & h; \\r
+ t15 = t3 ^ f; \\r
+ t16 = e ^ t14; \\r
+ g = t15 ^ t16\r
+\r
+#define k_xor(r,a,b,c,d) \\r
+ a ^= l_key[4 * r + 8]; \\r
+ b ^= l_key[4 * r + 9]; \\r
+ c ^= l_key[4 * r + 10]; \\r
+ d ^= l_key[4 * r + 11]\r
+\r
+#define k_set(r,a,b,c,d) \\r
+ a = l_key[4 * r + 8]; \\r
+ b = l_key[4 * r + 9]; \\r
+ c = l_key[4 * r + 10]; \\r
+ d = l_key[4 * r + 11]\r
+\r
+#define k_get(r,a,b,c,d) \\r
+ l_key[4 * r + 8] = a; \\r
+ l_key[4 * r + 9] = b; \\r
+ l_key[4 * r + 10] = c; \\r
+ l_key[4 * r + 11] = d\r
+\r
+/* the linear transformation and its inverse */\r
+\r
+#define rot(a,b,c,d) \\r
+ a = rotl(a, 13); \\r
+ c = rotl(c, 3); \\r
+ d ^= c ^ (a << 3); \\r
+ b ^= a ^ c; \\r
+ d = rotl(d, 7); \\r
+ b = rotl(b, 1); \\r
+ a ^= b ^ d; \\r
+ c ^= d ^ (b << 7); \\r
+ a = rotl(a, 5); \\r
+ c = rotl(c, 22)\r
+\r
+#define irot(a,b,c,d) \\r
+ c = rotr(c, 22); \\r
+ a = rotr(a, 5); \\r
+ c ^= d ^ (b << 7); \\r
+ a ^= b ^ d; \\r
+ d = rotr(d, 7); \\r
+ b = rotr(b, 1); \\r
+ d ^= c ^ (a << 3); \\r
+ b ^= a ^ c; \\r
+ c = rotr(c, 3); \\r
+ a = rotr(a, 13)\r
+\r
+/* initialise the key schedule from the user supplied key */\r
+\r
+u4byte *serpent_set_key(SerpentContext *ctx,\r
+ const u4byte in_key[], const u4byte key_len)\r
+{ \r
+ u4byte i,lk,a,b,c,d,e,f,g,h;\r
+ u4byte t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+ if(key_len < 0 || key_len > 256)\r
+\r
+ return (u4byte*)0;\r
+\r
+ i = 0; lk = (key_len + 31) / 32;\r
+ \r
+ while(i < lk)\r
+ {\r
+#ifdef BLOCK_SWAP\r
+ l_key[i] = io_swap(in_key[lk - i - 1]);\r
+#else\r
+ l_key[i] = in_key[i];\r
+#endif \r
+ i++;\r
+ }\r
+\r
+ if(key_len < 256)\r
+ {\r
+ while(i < 8)\r
+\r
+ l_key[i++] = 0;\r
+\r
+ i = key_len / 32; lk = 1 << key_len % 32; \r
+\r
+ l_key[i] = l_key[i] & (lk - 1) | lk;\r
+ }\r
+\r
+ for(i = 0; i < 132; ++i)\r
+ {\r
+ lk = l_key[i] ^ l_key[i + 3] ^ l_key[i + 5] \r
+ ^ l_key[i + 7] ^ 0x9e3779b9 ^ i;\r
+\r
+ l_key[i + 8] = (lk << 11) | (lk >> 21); \r
+ }\r
+\r
+ k_set( 0,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( 0,e,f,g,h);\r
+ k_set( 1,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( 1,e,f,g,h);\r
+ k_set( 2,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get( 2,e,f,g,h);\r
+ k_set( 3,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get( 3,e,f,g,h);\r
+ k_set( 4,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get( 4,e,f,g,h);\r
+ k_set( 5,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get( 5,e,f,g,h);\r
+ k_set( 6,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get( 6,e,f,g,h);\r
+ k_set( 7,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get( 7,e,f,g,h);\r
+ k_set( 8,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( 8,e,f,g,h);\r
+ k_set( 9,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( 9,e,f,g,h);\r
+ k_set(10,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(10,e,f,g,h);\r
+ k_set(11,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(11,e,f,g,h);\r
+ k_set(12,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(12,e,f,g,h);\r
+ k_set(13,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(13,e,f,g,h);\r
+ k_set(14,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(14,e,f,g,h);\r
+ k_set(15,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(15,e,f,g,h);\r
+ k_set(16,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(16,e,f,g,h);\r
+ k_set(17,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get(17,e,f,g,h);\r
+ k_set(18,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(18,e,f,g,h);\r
+ k_set(19,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(19,e,f,g,h);\r
+ k_set(20,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(20,e,f,g,h);\r
+ k_set(21,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(21,e,f,g,h);\r
+ k_set(22,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(22,e,f,g,h);\r
+ k_set(23,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(23,e,f,g,h);\r
+ k_set(24,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(24,e,f,g,h);\r
+ k_set(25,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get(25,e,f,g,h);\r
+ k_set(26,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(26,e,f,g,h);\r
+ k_set(27,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(27,e,f,g,h);\r
+ k_set(28,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(28,e,f,g,h);\r
+ k_set(29,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(29,e,f,g,h);\r
+ k_set(30,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(30,e,f,g,h);\r
+ k_set(31,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(31,e,f,g,h);\r
+ k_set(32,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(32,e,f,g,h);\r
+\r
+ return l_key;\r
+};\r
+\r
+/* encrypt a block of text */\r
+\r
+void serpent_encrypt(SerpentContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[])\r
+{ \r
+ u4byte a,b,c,d,e,f,g,h;\r
+ u4byte t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
+ u4byte *l_key = ctx->l_key;\r
+\r
+#ifdef BLOCK_SWAP\r
+ a = io_swap(in_blk[3]); b = io_swap(in_blk[2]); \r
+ c = io_swap(in_blk[1]); d = io_swap(in_blk[0]);\r
+#else\r
+ a = in_blk[0]; b = in_blk[1]; c = in_blk[2]; d = in_blk[3];\r
+#endif\r
+\r
+ k_xor( 0,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor( 1,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor( 2,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor( 3,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor( 4,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor( 5,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor( 6,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor( 7,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor( 8,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor( 9,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(10,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(11,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(12,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(13,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(14,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(15,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(16,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(17,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(18,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(19,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(20,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(21,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(22,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(23,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(24,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(25,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(26,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(27,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(28,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(29,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+ k_xor(30,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+ k_xor(31,e,f,g,h); sb7(e,f,g,h,a,b,c,d); k_xor(32,a,b,c,d); \r
+ \r
+#ifdef BLOCK_SWAP\r
+ out_blk[3] = io_swap(a); out_blk[2] = io_swap(b); \r
+ out_blk[1] = io_swap(c); out_blk[0] = io_swap(d);\r
+#else\r
+ out_blk[0] = a; out_blk[1] = b; out_blk[2] = c; out_blk[3] = d;\r
+#endif\r
+};\r
+\r
+/* decrypt a block of text */\r
+\r
+void serpent_decrypt(SerpentContext *ctx,\r
+ const u4byte in_blk[4], u4byte out_blk[4])\r
+{ \r
+ u4byte a,b,c,d,e,f,g,h;\r
+ u4byte t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
+ u4byte *l_key = ctx->l_key;\r
+ \r
+#ifdef BLOCK_SWAP\r
+ a = io_swap(in_blk[3]); b = io_swap(in_blk[2]); \r
+ c = io_swap(in_blk[1]); d = io_swap(in_blk[0]);\r
+#else\r
+ a = in_blk[0]; b = in_blk[1]; c = in_blk[2]; d = in_blk[3];\r
+#endif\r
+\r
+ k_xor(32,a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(31,e,f,g,h);\r
+ irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(30,a,b,c,d);\r
+ irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(29,e,f,g,h);\r
+ irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(28,a,b,c,d);\r
+ irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(27,e,f,g,h);\r
+ irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(26,a,b,c,d);\r
+ irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(25,e,f,g,h);\r
+ irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(24,a,b,c,d);\r
+ irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(23,e,f,g,h);\r
+ irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(22,a,b,c,d);\r
+ irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(21,e,f,g,h);\r
+ irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(20,a,b,c,d);\r
+ irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(19,e,f,g,h);\r
+ irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(18,a,b,c,d);\r
+ irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(17,e,f,g,h);\r
+ irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(16,a,b,c,d);\r
+ irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(15,e,f,g,h);\r
+ irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(14,a,b,c,d);\r
+ irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(13,e,f,g,h);\r
+ irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(12,a,b,c,d);\r
+ irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(11,e,f,g,h);\r
+ irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(10,a,b,c,d);\r
+ irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 9,e,f,g,h);\r
+ irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 8,a,b,c,d);\r
+ irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor( 7,e,f,g,h);\r
+ irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor( 6,a,b,c,d);\r
+ irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor( 5,e,f,g,h);\r
+ irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor( 4,a,b,c,d);\r
+ irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor( 3,e,f,g,h);\r
+ irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor( 2,a,b,c,d);\r
+ irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 1,e,f,g,h);\r
+ irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 0,a,b,c,d);\r
+ \r
+#ifdef BLOCK_SWAP\r
+ out_blk[3] = io_swap(a); out_blk[2] = io_swap(b); \r
+ out_blk[1] = io_swap(c); out_blk[0] = io_swap(d);\r
+#else\r
+ out_blk[0] = a; out_blk[1] = b; out_blk[2] = c; out_blk[3] = d;\r
+#endif\r
+};\r
--- /dev/null
+/*
+
+ serpent.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef SERPENT_H
+#define SERPENT_H
+
+#include "serpent_internal.h"
+
+/*
+ * SILC Crypto API for Serpent
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_serpent_init(void *context,
+ const unsigned char *key,
+ size_t keylen)
+{
+ serpent_set_key((SerpentContext *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+inline int silc_serpent_set_string_as_key(void *context,
+ const unsigned char *string,
+ size_t keylen)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+
+ return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_serpent_context_len()
+{
+ return sizeof(SerpentContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_serpent_encrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ serpent_encrypt((SerpentContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ serpent_encrypt((SerpentContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_serpent_decrypt_cbc(void *context,
+ const unsigned char *src,
+ unsigned char *dst,
+ size_t len,
+ unsigned char *iv)
+{
+ unsigned int *in, *out, *tiv;
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ serpent_decrypt((SerpentContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ serpent_decrypt((SerpentContext *)context, in, out);
+ out[0] ^= in[0 - 4];
+ out[1] ^= in[1 - 4];
+ out[2] ^= in[2 - 4];
+ out[3] ^= in[3 - 4];
+ in += 4;
+ out += 4;
+ }
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+
+ serpent_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SERPENT_INTERNAL_H
+#define SERPENT_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+ u4byte l_key[140];
+} SerpentContext;
+
+/* Prototypes */
+u4byte *serpent_set_key(SerpentContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void serpent_encrypt(SerpentContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[]);
+void serpent_decrypt(SerpentContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+
+#include "silcincludes.h"
+#include "sha1.h"
+
+/*
+ * SILC Hash API for SHA1
+ */
+
+SILC_HASH_API_INIT(sha1)
+{
+ SHA1Init((SHA1_CTX *)context);
+}
+
+SILC_HASH_API_UPDATE(sha1)
+{
+ SHA1Update((SHA1_CTX *)context, data, len);
+}
+
+SILC_HASH_API_FINAL(sha1)
+{
+ SHA1Final(digest, (SHA1_CTX *)context);
+}
+
+SILC_HASH_API_TRANSFORM(sha1)
+{
+ SHA1Transform(state, buffer);
+}
+
+SILC_HASH_API_CONTEXT_LEN(sha1)
+{
+ return sizeof(SHA1_CTX);
+}
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
+{
+unsigned long a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ unsigned long l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
+{
+unsigned int i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned long i, j;
+unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+
+/*************************************************************/
+
+/* Test Code */
+
+#if 0
+
+int main(int argc, char** argv)
+{
+int i, j;
+SHA1_CTX context;
+unsigned char digest[20], buffer[16384];
+FILE* file;
+
+ if (argc > 2) {
+ puts("Public domain SHA-1 implementation - by Steve Reid <steve@edmweb.com>");
+ puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
+ exit(0);
+ }
+ if (argc < 2) {
+ file = stdin;
+ }
+ else {
+ if (!(file = fopen(argv[1], "rb"))) {
+ fputs("Unable to open file.", stderr);
+ exit(-1);
+ }
+ }
+ SHA1Init(&context);
+ while (!feof(file)) { /* note: what if ferror(file) */
+ i = fread(buffer, 1, 16384, file);
+ SHA1Update(&context, buffer, i);
+ }
+ SHA1Final(digest, &context);
+ fclose(file);
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 4; j++) {
+ printf("%02X", digest[i*4+j]);
+ }
+ putchar(' ');
+ }
+ putchar('\n');
+ exit(0);
+}
+
+#endif
--- /dev/null
+/*
+
+ sha1.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef SHA1_H
+#define SHA1_H
+
+#include "sha1_internal.h"
+
+/*
+ * SILC Hash API for SHA1
+ */
+
+SILC_HASH_API_INIT(sha1);
+SILC_HASH_API_UPDATE(sha1);
+SILC_HASH_API_FINAL(sha1);
+SILC_HASH_API_TRANSFORM(sha1);
+SILC_HASH_API_CONTEXT_LEN(sha1);
+
+#endif
--- /dev/null
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+/* Header portion split from main code for convenience (AYB 3/02/98) */
+
+#ifndef SHA1_INTERNAL_H
+#define SHA1_INTERNAL_H
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* Context declaration */
+typedef struct {
+ unsigned long state[5];
+ unsigned long count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+/* Function forward declerations */
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#endif
--- /dev/null
+/*
+
+ silccipher.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:54 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#include "ciphers.h" /* Includes cipher definitions */
+
+/* List of all ciphers in SILC. You can dynamically add new ciphers
+ into the list. At the initialization of SILC this list is filled with
+ the configured ciphers. */
+struct SilcCipherListStruct {
+ SilcCipherObject *cipher;
+ struct SilcCipherListStruct *next;
+};
+
+/* Dynamically registered list of ciphers. */
+struct SilcCipherListStruct *silc_cipher_list = NULL;
+
+/* XXX: add the other good ciphers here as well */
+
+/* Staticly declared list of ciphers. This is used if system doesn't
+ support SIM's. */
+SilcCipherObject silc_cipher_builtin_list[] =
+{
+ { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
+ silc_none_encrypt_cbc, silc_none_decrypt_cbc,
+ silc_none_context_len },
+ { "twofish", 16, 16, silc_twofish_set_key, silc_twofish_set_key_with_string,
+ silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
+ silc_twofish_context_len },
+ { "rc6", 16, 16, silc_rc6_set_key, silc_rc6_set_key_with_string,
+ silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc,
+ silc_rc6_context_len },
+ { "mars", 16, 16, silc_mars_set_key, silc_mars_set_key_with_string,
+ silc_mars_encrypt_cbc, silc_mars_decrypt_cbc,
+ silc_mars_context_len },
+
+ { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* Register a new cipher into SILC. This is used at the initialization of
+ the SILC. This function allocates a new object for the cipher to be
+ registered. Therefore, if memory has been allocated for the object sent
+ as argument it has to be free'd after this function returns succesfully. */
+
+int silc_cipher_register(SilcCipherObject *cipher)
+{
+ struct SilcCipherListStruct *new, *c;
+
+ SILC_LOG_DEBUG(("Registering new cipher"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new cipher list object: %s",
+ strerror(errno)));
+ return FALSE;
+ }
+
+ new->cipher = silc_calloc(1, sizeof(*new->cipher));
+ if (!new->cipher) {
+ SILC_LOG_ERROR(("Could not allocate new cipher object: %s",
+ strerror(errno)));
+ return FALSE;
+ }
+
+ /* Set the pointers */
+ new->cipher->name = strdup(cipher->name);
+ new->cipher->block_len = cipher->block_len;
+ new->cipher->key_len = cipher->key_len;
+ new->cipher->set_key = cipher->set_key;
+ new->cipher->set_key_with_string = cipher->set_key_with_string;
+ new->cipher->encrypt = cipher->encrypt;
+ new->cipher->decrypt = cipher->decrypt;
+ new->cipher->context_len = cipher->context_len;
+ new->next = NULL;
+
+ /* Add the new cipher to the list */
+ if (!silc_cipher_list) {
+ silc_cipher_list = new;
+ return TRUE;
+ }
+
+ c = silc_cipher_list;
+ while (c) {
+ if (!c->next) {
+ c->next = new;
+ break;
+ }
+ c = c->next;
+ }
+
+ return TRUE;
+}
+
+/* Unregister a cipher from the SILC. */
+
+int silc_cipher_unregister(SilcCipherObject *cipher)
+{
+ struct SilcCipherListStruct *c, *tmp;
+
+ SILC_LOG_DEBUG(("Unregistering cipher"));
+
+ c = silc_cipher_list;
+
+ if (cipher == SILC_ALL_CIPHERS) {
+ /* Unregister all ciphers */
+ while (c) {
+ tmp = c->next;
+ silc_free(c->cipher->name);
+ silc_free(c);
+ c = tmp;
+ }
+
+ return TRUE;
+ }
+
+ /* Unregister the cipher */
+ if (c->cipher == cipher) {
+ tmp = c->next;
+ silc_free(c->cipher->name);
+ silc_free(c);
+ silc_cipher_list = tmp;
+
+ return TRUE;
+ }
+
+ while (c) {
+ if (c->next->cipher == cipher) {
+
+ tmp = c->next->next;
+ silc_free(c->cipher->name);
+ silc_free(c);
+ c->next = tmp;
+
+ return TRUE;
+ }
+
+ c = c->next;
+ }
+
+ return FALSE;
+}
+
+/* Allocates a new SILC cipher object. Function returns 1 on succes and 0
+ on error. The allocated cipher is returned in new_cipher argument. The
+ caller must set the key to the cipher after this function has returned
+ by calling the ciphers set_key function. */
+
+int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
+{
+ struct SilcCipherListStruct *c;
+ int i;
+
+ SILC_LOG_DEBUG(("Allocating new cipher object"));
+
+ /* Allocate the new object */
+ *new_cipher = silc_calloc(1, sizeof(**new_cipher));
+ if (*new_cipher == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new cipher object"));
+ return FALSE;
+ }
+
+ if (silc_cipher_list) {
+
+ c = silc_cipher_list;
+ while (c) {
+ if (!strcmp(c->cipher->name, name))
+ break;
+ c = c->next;
+ }
+
+ if (!c)
+ goto check_builtin;
+
+ /* Set the pointers */
+ (*new_cipher)->cipher = c->cipher;
+ (*new_cipher)->context = silc_calloc(1, c->cipher->context_len());
+ (*new_cipher)->set_iv = silc_cipher_set_iv;
+ (*new_cipher)->get_iv = silc_cipher_get_iv;
+ (*new_cipher)->get_key_len = silc_cipher_get_key_len;
+ (*new_cipher)->get_block_len = silc_cipher_get_block_len;
+
+ return TRUE;
+ }
+
+ check_builtin:
+
+ for (i = 0; silc_cipher_builtin_list[i].name; i++)
+ if (!strcmp(silc_cipher_builtin_list[i].name, name))
+ break;
+
+ if (silc_cipher_builtin_list[i].name == NULL) {
+ silc_free(*new_cipher);
+ return FALSE;
+ }
+
+ /* Set the pointers */
+ (*new_cipher)->cipher = &silc_cipher_builtin_list[i];
+ (*new_cipher)->context =
+ silc_calloc(1, (*new_cipher)->cipher->context_len());
+ (*new_cipher)->set_iv = silc_cipher_set_iv;
+ (*new_cipher)->get_iv = silc_cipher_get_iv;
+ (*new_cipher)->get_key_len = silc_cipher_get_key_len;
+ (*new_cipher)->get_block_len = silc_cipher_get_block_len;
+ memset(&(*new_cipher)->iv, 0, sizeof((*new_cipher)->iv));
+
+ return TRUE;
+}
+
+/* Free's the given cipher. */
+
+void silc_cipher_free(SilcCipher cipher)
+{
+ if (cipher) {
+ silc_free(cipher->context);
+ silc_free(cipher);
+ }
+}
+
+/* Returns TRUE if cipher `name' is supported. */
+
+int silc_cipher_is_supported(const unsigned char *name)
+{
+ struct SilcCipherListStruct *c;
+ int i;
+
+ if (silc_cipher_list) {
+ c = silc_cipher_list;
+
+ while (c) {
+ if (!strcmp(c->cipher->name, name))
+ return TRUE;
+ c = c->next;
+ }
+ }
+
+ for (i = 0; silc_cipher_builtin_list[i].name; i++)
+ if (!strcmp(silc_cipher_builtin_list[i].name, name))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Returns comma separated list of supported ciphers. */
+
+char *silc_cipher_get_supported()
+{
+ char *list = NULL;
+ int i, len;
+ struct SilcCipherListStruct *c;
+
+ len = 0;
+ if (silc_cipher_list) {
+ c = silc_cipher_list;
+
+ while (c) {
+ len += strlen(c->cipher->name);
+ list = silc_realloc(list, len + 1);
+
+ memcpy(list + (len - strlen(c->cipher->name)),
+ c->cipher->name, strlen(c->cipher->name));
+ memcpy(list + len, ",", 1);
+ len++;
+
+ c = c->next;
+ }
+ }
+
+ for (i = 0; silc_cipher_builtin_list[i].name; i++) {
+ len += strlen(silc_cipher_builtin_list[i].name);
+ list = silc_realloc(list, len + 1);
+
+ memcpy(list + (len - strlen(silc_cipher_builtin_list[i].name)),
+ silc_cipher_builtin_list[i].name,
+ strlen(silc_cipher_builtin_list[i].name));
+ memcpy(list + len, ",", 1);
+ len++;
+ }
+
+ list[len - 1] = 0;
+
+ return list;
+}
+
+/* Sets the IV (initial vector) for the cipher. */
+
+void silc_cipher_set_iv(SilcCipher itself, const unsigned char *iv)
+{
+ memset(&itself->iv, 0, sizeof(itself->iv));
+ memcpy(&itself->iv, iv, itself->cipher->block_len);
+}
+
+/* Returns the IV (initial vector) of the cipher. The IV is returned
+ to 'iv' argument. */
+
+void silc_cipher_get_iv(SilcCipher itself, unsigned char *iv)
+{
+ memcpy(iv, &itself->iv, itself->cipher->block_len);
+}
+
+/* Returns the key length of the cipher. */
+/* XXX */
+
+unsigned int silc_cipher_get_key_len(SilcCipher itself,
+ const unsigned char *name)
+{
+
+ return TRUE;
+}
+
+/* Returns the block size of the cipher. */
+/* XXX */
+
+unsigned int silc_cipher_get_block_len(SilcCipher itself)
+{
+
+ return TRUE;
+}
--- /dev/null
+/*
+
+ silccipher.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCIPHER_H
+#define SILCCIPHER_H
+
+/*
+ SILC Cipher object.
+
+ Default SILC cipher object to represent any cipher. The function
+ pointers are the stub functions for each implemented cipher. Following
+ short description of the fields:
+
+ char *name
+
+ Logical name of the cipher.
+
+ unsigned int block_len
+
+ Block size of the cipher.
+
+ unsigned int key_len
+
+ Length of the key of the cipher (in bits).
+
+*/
+typedef struct {
+ char *name;
+ unsigned int block_len;
+ unsigned key_len;
+
+ int (*set_key)(void *, const unsigned char *, unsigned int);
+ int (*set_key_with_string)(void *, const unsigned char *, unsigned int);
+ int (*encrypt)(void *, const unsigned char *, unsigned char *,
+ unsigned int, unsigned char *);
+ int (*decrypt)(void *, const unsigned char *, unsigned char *,
+ unsigned int, unsigned char *);
+ unsigned int (*context_len)();
+} SilcCipherObject;
+
+#define SILC_CIPHER_MAX_IV_SIZE 16
+
+/* The main SilcCipher structure. Use SilcCipher instead of SilcCipherStruct.
+ Also remember that SilcCipher is a pointer. */
+typedef struct SilcCipherStruct {
+ SilcCipherObject *cipher;
+ void *context;
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
+
+ void (*set_iv)(struct SilcCipherStruct *, const unsigned char *);
+ void (*get_iv)(struct SilcCipherStruct *, unsigned char *);
+ unsigned int (*get_key_len)(struct SilcCipherStruct *,
+ const unsigned char *);
+ unsigned int (*get_block_len)(struct SilcCipherStruct *);
+} *SilcCipher;
+
+/* List of all registered ciphers. */
+extern struct SilcCipherListStruct *silc_cipher_list;
+
+/* Marks for all ciphers in silc. This can be used in silc_cipher_unregister
+ to unregister all ciphers at once. */
+#define SILC_ALL_CIPHERS ((SilcCipherObject *)1)
+
+/* Macros */
+
+/* Function names in SILC Crypto modules. The name of the cipher
+ is appended into these names and used to the get correct symbol out
+ of the module. All SILC Crypto API compliant modules must support
+ these function names (use macros below to assure this). */
+#define SILC_CIPHER_SIM_SET_KEY "set_key"
+#define SILC_CIPHER_SIM_SET_KEY_WITH_STRING "set_key_with_string"
+#define SILC_CIPHER_SIM_ENCRYPT_CBC "encrypt_cbc"
+#define SILC_CIPHER_SIM_DECRYPT_CBC "decrypt_cbc"
+#define SILC_CIPHER_SIM_CONTEXT_LEN "context_len"
+
+/* These macros can be used to implement the SILC Crypto API and to avoid
+ errors in the API these macros should be used always. */
+#define SILC_CIPHER_API_SET_KEY(cipher) \
+int silc_##cipher##_set_key(void *context, \
+ const unsigned char *key, \
+ unsigned int keylen)
+#define SILC_CIPHER_API_SET_KEY_WITH_STRING(cipher) \
+int silc_##cipher##_set_key_with_string(void *context, \
+ const unsigned char *string, \
+ unsigned int stringlen)
+#define SILC_CIPHER_API_ENCRYPT_CBC(cipher) \
+int silc_##cipher##_encrypt_cbc(void *context, \
+ const unsigned char *src, \
+ unsigned char *dst, \
+ unsigned int len, \
+ unsigned char *iv)
+#define SILC_CIPHER_API_DECRYPT_CBC(cipher) \
+int silc_##cipher##_decrypt_cbc(void *context, \
+ const unsigned char *src, \
+ unsigned char *dst, \
+ unsigned int len, \
+ unsigned char *iv)
+#define SILC_CIPHER_API_CONTEXT_LEN(cipher) \
+unsigned int silc_##cipher##_context_len()
+
+/* Prototypes */
+int silc_cipher_register(SilcCipherObject *cipher);
+int silc_cipher_unregister(SilcCipherObject *cipher);
+int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher);
+void silc_cipher_free(SilcCipher cipher);
+int silc_cipher_is_supported(const unsigned char *name);
+char *silc_cipher_get_supported();
+void silc_cipher_set_iv(SilcCipher itself, const unsigned char *iv);
+void silc_cipher_get_iv(SilcCipher itself, unsigned char *iv);
+unsigned int silc_cipher_get_key_len(SilcCipher itself,
+ const unsigned char *name);
+unsigned int silc_cipher_get_block_len(SilcCipher itself);
+
+#endif
--- /dev/null
+/*
+
+ silchash.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#include "md5.h"
+#include "sha1.h"
+
+/* List of all hash functions in SILC. You can dynamically add new hash
+ functions into the list. At the initialization of SILC this list is
+ filled with the configured hash functions. */
+struct SilcHashListStruct {
+ SilcHashObject *hash;
+ struct SilcHashListStruct *next;
+};
+
+/* List of dynamically registered hash functions. */
+struct SilcHashListStruct *silc_hash_list = NULL;
+
+/* Statically declared list of hash functions. */
+SilcHashObject silc_hash_builtin_list[] =
+{
+ { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
+ silc_md5_transform, silc_md5_context_len },
+ { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
+ silc_sha1_transform, silc_sha1_context_len },
+
+ { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* Registers a ned hash function into the SILC. This function is used at
+ the initialization of the SILC. */
+
+int silc_hash_register(SilcHashObject *hash)
+{
+ struct SilcHashListStruct *new, *h;
+
+ SILC_LOG_DEBUG(("Registering new hash function"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new hash list object"));
+ return FALSE;
+ }
+
+ new->hash = silc_calloc(1, sizeof(*new->hash));
+ if (!new->hash) {
+ SILC_LOG_ERROR(("Could not allocate new hash object"));
+ return FALSE;
+ }
+
+ /* Set the pointers */
+ new->hash->name = silc_calloc(1, strlen(hash->name));
+ memcpy(new->hash->name, hash->name, strlen(hash->name));
+ new->hash->hash_len = hash->hash_len;
+ new->hash->block_len = hash->block_len;
+ new->hash->init = hash->init;
+ new->hash->update = hash->update;
+ new->hash->final = hash->final;
+ new->hash->context_len = hash->context_len;
+ new->next = NULL;
+
+ /* Add the new hash function to the list */
+ if (!silc_hash_list) {
+ silc_hash_list = new;
+ return TRUE;
+ }
+
+ h = silc_hash_list;
+ while (h) {
+ if (!h->next) {
+ h->next = new;
+ break;
+ }
+ h = h->next;
+ }
+
+ return TRUE;
+}
+
+/* Unregister a hash function from the SILC. */
+
+int silc_hash_unregister(SilcHashObject *hash)
+{
+ struct SilcHashListStruct *h, *tmp;
+
+ SILC_LOG_DEBUG(("Unregistering hash function"));
+
+ h = silc_hash_list;
+
+ /* Unregister all hash functions */
+ if (hash == SILC_ALL_HASH_FUNCTIONS) {
+ /* Unregister all ciphers */
+ while (h) {
+ tmp = h->next;
+ silc_free(h->hash->name);
+ silc_free(h);
+ h = tmp;
+ }
+
+ return TRUE;
+ }
+
+ /* Unregister the hash function */
+ if (h->hash == hash) {
+ tmp = h->next;
+ silc_free(h->hash->name);
+ silc_free(h);
+ silc_hash_list = tmp;
+
+ return TRUE;
+ }
+
+ while (h) {
+ if (h->next->hash == hash) {
+ tmp = h->next->next;
+ silc_free(h->hash->name);
+ silc_free(h);
+ h->next = tmp;
+ return TRUE;
+ }
+
+ h = h->next;
+ }
+
+ return FALSE;
+}
+
+/* Allocates a new SilcHash object. New object is returned into new_hash
+ argument. */
+
+int silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
+{
+ struct SilcHashListStruct *h;
+ int i;
+
+ SILC_LOG_DEBUG(("Allocating new hash object"));
+
+ /* Allocate the new object */
+ *new_hash = silc_calloc(1, sizeof(**new_hash));
+ if (*new_hash == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new hash object"));
+ return FALSE;
+ }
+
+ if (silc_hash_list) {
+ h = silc_hash_list;
+ while (h) {
+ if (!strcmp(h->hash->name, name))
+ break;
+ h = h->next;
+ }
+
+ if (!h)
+ goto check_builtin;
+
+ /* Set the pointers */
+ (*new_hash)->hash = h->hash;
+ (*new_hash)->context = silc_calloc(1, h->hash->context_len());
+ (*new_hash)->make_hash = silc_hash_make;
+
+ return TRUE;
+ }
+
+ check_builtin:
+ for (i = 0; silc_hash_builtin_list[i].name; i++)
+ if (!strcmp(silc_hash_builtin_list[i].name, name))
+ break;
+
+ if (silc_hash_builtin_list[i].name == NULL) {
+ silc_free(*new_hash);
+ return FALSE;
+ }
+
+ /* Set the pointers */
+ (*new_hash)->hash = &silc_hash_builtin_list[i];
+ (*new_hash)->context = silc_calloc(1, (*new_hash)->hash->context_len());
+ (*new_hash)->make_hash = silc_hash_make;
+
+ return TRUE;
+}
+
+/* Free's the SilcHash object */
+
+void silc_hash_free(SilcHash hash)
+{
+ if (hash) {
+ silc_free(hash->context);
+ silc_free(hash);
+ }
+}
+
+/* Returns TRUE if hash algorithm `name' is supported. */
+
+int silc_hash_is_supported(const unsigned char *name)
+{
+ struct SilcHashListStruct *h;
+ int i;
+
+ if (silc_hash_list) {
+ h = silc_hash_list;
+
+ while (h) {
+ if (!strcmp(h->hash->name, name))
+ return TRUE;
+ h = h->next;
+ }
+ }
+
+ for (i = 0; silc_hash_builtin_list[i].name; i++)
+ if (!strcmp(silc_hash_builtin_list[i].name, name))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Returns comma separated list of supported hash functions. */
+
+char *silc_hash_get_supported()
+{
+ char *list = NULL;
+ int i, len;
+ struct SilcHashListStruct *h;
+
+ len = 0;
+ if (silc_hash_list) {
+ h = silc_hash_list;
+
+ while (h) {
+ len += strlen(h->hash->name);
+ list = silc_realloc(list, len + 1);
+
+ memcpy(list + (len - strlen(h->hash->name)),
+ h->hash->name, strlen(h->hash->name));
+ memcpy(list + len, ",", 1);
+ len++;
+
+ h = h->next;
+ }
+ }
+
+ for (i = 0; silc_hash_builtin_list[i].name; i++) {
+ len += strlen(silc_hash_builtin_list[i].name);
+ list = silc_realloc(list, len + 1);
+
+ memcpy(list + (len - strlen(silc_hash_builtin_list[i].name)),
+ silc_hash_builtin_list[i].name,
+ strlen(silc_hash_builtin_list[i].name));
+ memcpy(list + len, ",", 1);
+ len++;
+ }
+
+ list[len - 1] = 0;
+
+ return list;
+}
+
+/* Creates the hash value and returns it to the return_hash argument. */
+
+void silc_hash_make(SilcHash hash, const unsigned char *data,
+ unsigned int len, unsigned char *return_hash)
+{
+ hash->hash->init(hash->context);
+ hash->hash->update(hash->context, (unsigned char *)data, len);
+ hash->hash->final(hash->context, return_hash);
+}
--- /dev/null
+/*
+
+ silchash.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCHASH_H
+#define SILCHASH_H
+
+/* The default Silc hash object to represent any hash function in SILC. */
+typedef struct {
+ char *name;
+ unsigned int hash_len;
+ unsigned int block_len;
+
+ void (*init)(void *);
+ void (*update)(void *, unsigned char *, unsigned int);
+ void (*final)(void *, unsigned char *);
+ void (*transform)(unsigned long *, unsigned char *);
+ unsigned int (*context_len)();
+} SilcHashObject;
+
+/* The main SILC hash structure. Use SilcHash instead of SilcHashStruct.
+ Also remember that SilcHash is a pointer. */
+typedef struct SilcHashStruct {
+ SilcHashObject *hash;
+ void *context;
+
+ void (*make_hash)(struct SilcHashStruct *, const unsigned char *,
+ unsigned int, unsigned char *);
+} *SilcHash;
+
+extern struct SilcHashListStruct *silc_hash_list;
+
+/* Marks for all hash functions. This can be used in silc_hash_unregister
+ to unregister all hash function at once. */
+#define SILC_ALL_HASH_FUNCTIONS ((SilcHashObject *)1)
+
+/* Macros */
+
+/* Following macros are used to implement the SILC Hash API. These
+ macros should be used instead of declaring functions by hand. */
+
+/* Function names in SILC Hash modules. The name of the hash function
+ is appended into these names and used to the get correct symbol out
+ of the module. All SILC Hash API compliant modules has to support
+ these names as function names (use macros below to assure this). */
+#define SILC_HASH_SIM_INIT "init"
+#define SILC_HASH_SIM_UPDATE "update"
+#define SILC_HASH_SIM_FINAL "final"
+#define SILC_HASH_SIM_TRANSFORM "transform"
+#define SILC_HASH_SIM_CONTEXT_LEN "context_len"
+
+/* Macros that can be used to declare SILC Hash API functions. */
+#define SILC_HASH_API_INIT(hash) \
+void silc_##hash##_init(void *context)
+#define SILC_HASH_API_UPDATE(hash) \
+void silc_##hash##_update(void *context, unsigned char *data, \
+ unsigned int len)
+#define SILC_HASH_API_FINAL(hash) \
+void silc_##hash##_final(void *context, unsigned char *digest)
+#define SILC_HASH_API_TRANSFORM(hash) \
+void silc_##hash##_transform(unsigned long *state, \
+ unsigned char *buffer)
+#define SILC_HASH_API_CONTEXT_LEN(hash) \
+unsigned int silc_##hash##_context_len()
+
+/* Prototypes */
+int silc_hash_register(SilcHashObject *hash);
+int silc_hash_unregister(SilcHashObject *hash);
+int silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
+void silc_hash_free(SilcHash hash);
+int silc_hash_is_supported(const unsigned char *name);
+char *silc_hash_get_supported();
+void silc_hash_make(SilcHash hash, const unsigned char *data,
+ unsigned int len, unsigned char *return_hash);
+
+#endif
--- /dev/null
+/*
+
+ silchmac.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Allocates a new SilcHmac object. First argument is the hash function
+ object to tell the hmac which hash function should be used when creating
+ HMAC's. The new SilcHmac object is returned to new_hmac argument. */
+
+int silc_hmac_alloc(SilcHash hash, SilcHmac *new_hmac)
+{
+ SILC_LOG_DEBUG(("Allocating new hmac object"));
+
+ *new_hmac = silc_calloc(1, sizeof(**new_hmac));
+ if (*new_hmac == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new hmac object"));
+ return 0;
+ }
+
+ (*new_hmac)->hash = hash;
+ (*new_hmac)->set_key = silc_hmac_set_key;
+ (*new_hmac)->make_hmac = silc_hmac_make;
+ (*new_hmac)->make_hmac_with_key = silc_hmac_make_with_key;
+ (*new_hmac)->make_hmac_truncated = silc_hmac_make_truncated;
+
+ return 1;
+}
+
+/* Free's the SilcHmac object. */
+
+void silc_hmac_free(SilcHmac hmac)
+{
+ if (hmac)
+ silc_free(hmac);
+}
+
+/* Creates the HMAC. The created keyed hash value is returned to
+ return_hash argument. */
+
+void silc_hmac_make_internal(SilcHmac hmac, unsigned char *data,
+ unsigned int data_len, unsigned char *key,
+ unsigned int key_len, unsigned char *return_hash)
+{
+ SilcHash hash = hmac->hash;
+ unsigned char inner_pad[hash->hash->block_len + 1];
+ unsigned char outer_pad[hash->hash->block_len + 1];
+ unsigned char hvalue[hash->hash->hash_len];
+ void *hash_context;
+ int i;
+
+ SILC_LOG_DEBUG(("Making HMAC for message"));
+
+ hash_context = silc_calloc(1, hash->hash->context_len());
+
+ memset(inner_pad, 0, sizeof(inner_pad));
+ memset(outer_pad, 0, sizeof(outer_pad));
+
+ /* If the key length is more than block size of the hash function, the
+ key is hashed. */
+ if (key_len > hash->hash->block_len) {
+ hash->make_hash(hash, key, key_len, hvalue);
+ key = hvalue;
+ key_len = hash->hash->hash_len;
+ }
+
+ /* Copy the key into the pads */
+ memcpy(inner_pad, key, key_len);
+ memcpy(outer_pad, key, key_len);
+
+ /* XOR the key with pads */
+ for (i = 0; i < hash->hash->block_len; i++) {
+ inner_pad[i] ^= 0x36;
+ outer_pad[i] ^= 0x5c;
+ }
+
+ /* Do the HMAC transform (too bad I can't do make_hash directly, sigh) */
+ hash->hash->init(hash_context);
+ hash->hash->update(hash_context, inner_pad, hash->hash->block_len);
+ hash->hash->update(hash_context, data, data_len);
+ hash->hash->final(hash_context, return_hash);
+ hash->hash->init(hash_context);
+ hash->hash->update(hash_context, outer_pad, hash->hash->block_len);
+ hash->hash->update(hash_context, return_hash, hash->hash->hash_len);
+ hash->hash->final(hash_context, return_hash);
+}
+
+/* Create the HMAC. This is thee make_hmac function pointer. This
+ uses the internal key set with silc_hmac_set_key. */
+
+void silc_hmac_make(SilcHmac hmac, unsigned char *data,
+ unsigned int data_len, unsigned char *return_hash)
+{
+ silc_hmac_make_internal(hmac, data, data_len, hmac->key,
+ hmac->key_len, return_hash);
+}
+
+/* Creates the HMAC just as above except that the hash value is truncated
+ to the truncated_len sent as argument. NOTE: One should not truncate to
+ less than half of the length of original hash value. However, this
+ routine allows these dangerous truncations. */
+
+void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
+ unsigned int data_len,
+ unsigned int truncated_len,
+ unsigned char *return_hash)
+{
+ unsigned char hvalue[hmac->hash->hash->hash_len];
+
+ silc_hmac_make_internal(hmac, data, data_len,
+ hmac->key, hmac->key_len, hvalue);
+ memcpy(return_hash, hvalue, truncated_len);
+ memset(hvalue, 0, sizeof(hvalue));
+}
+
+/* Creates HMAC just as above except that this doesn't use the internal
+ key. The key is sent as argument to the function. */
+
+void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
+ unsigned int data_len,
+ unsigned char *key, unsigned int key_len,
+ unsigned char *return_hash)
+{
+ silc_hmac_make_internal(hmac, data, data_len, key, key_len, return_hash);
+}
+
+/* Sets the HMAC key used in the HMAC creation */
+
+void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
+ unsigned int key_len)
+{
+ hmac->key = silc_calloc(key_len, sizeof(unsigned char));
+ memcpy(hmac->key, key, key_len);
+}
--- /dev/null
+/*
+
+ silchmac.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCHMAC_H
+#define SILCHMAC_H
+
+/*
+ SILC HMAC object.
+
+ This is the HMAC object to create keyed hash values for message
+ authentication. These routines uses already implemented hash functions.
+ HMAC's can be created using any hash function implemented in SILC. These
+ routines were created according to RFC2104. Following short description
+ of the fields:
+
+ SilcHash hash
+
+ The hash object to tell what hash function to use with this HMAC.
+
+ unsigned char *key
+ unsigned int len
+
+ The key and its length used to make the HMAC. This is set
+ with silc_hmac_set_key function.
+
+ void (*set_key)(SilcHmac, const unsigned char *, unsigned int)
+
+ Function used to set the key for the HMAC. Second argument is
+ the key to be set and last argument is the length of the key.
+
+ void (*make_hmac)(SilcHmac, unsigned char *, unsigned int,
+ unsigned char *)
+
+ Function what is used to create HMAC's. User can also use directly
+ silc_hmac_make fuction. Although, one needs to allocate a SilcHmac
+ object before doing it, naturally. This uses the key set with
+ silc_hmac_set_key function.
+
+ void (*make_hmac_with_key)(SilcHmac, unsigned char *, unsigned int,
+ unsigned char *, unsigned int, unsigned char *)
+
+ Same function as above except that the key used in the HMAC
+ creation is sent as argument. The key set with silc_hmac_set_key
+ is ignored in this case.
+
+ void (*make_hmac_truncated)(SilcHmac, unsigned char *, unsigned int,
+ unsigned int, unsigned char *)
+
+ Same function as above except that the output hash value is truncated
+ to the length sent as argument (second last argument). This makes
+ variable truncations possible, however, one should not truncate
+ hash values to less than half of the length of the hash value.
+
+*/
+typedef struct SilcHmacStruct *SilcHmac;
+
+struct SilcHmacStruct {
+ SilcHash hash;
+ unsigned char *key;
+ unsigned int key_len;
+ void (*set_key)(SilcHmac, const unsigned char *, unsigned int);
+ void (*make_hmac)(SilcHmac, unsigned char *, unsigned int,
+ unsigned char *);
+ void (*make_hmac_with_key)(SilcHmac, unsigned char *, unsigned int,
+ unsigned char *, unsigned int, unsigned char *);
+ void (*make_hmac_truncated)(SilcHmac, unsigned char *,
+ unsigned int, unsigned int, unsigned char *);
+};
+
+/* Prototypes */
+int silc_hmac_alloc(SilcHash hash, SilcHmac *new_hmac);
+void silc_hmac_free(SilcHmac hmac);
+void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
+ unsigned int key_len);
+void silc_hmac_make(SilcHmac hmac,
+ unsigned char *data,
+ unsigned int data_len,
+ unsigned char *return_hash);
+void silc_hmac_make_with_key(SilcHmac hmac,
+ unsigned char *data,
+ unsigned int data_len,
+ unsigned char *key,
+ unsigned int key_len,
+ unsigned char *return_hash);
+void silc_hmac_make_truncated(SilcHmac hmac,
+ unsigned char *data,
+ unsigned int data_len,
+ unsigned int truncated_len,
+ unsigned char *return_hash);
+
+#endif
--- /dev/null
+/*
+
+ silcpkcs.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+#include "rsa.h"
+
+/* List of all PKCS's in SILC. PKCS's don't support SIM's thus
+ only static declarations are possible. XXX: I hope this to change
+ real soon. */
+SilcPKCSObject silc_pkcs_list[] =
+{
+ { "rsa", &silc_rsa_data_context,
+ silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
+ silc_rsa_get_private_key, silc_rsa_set_public_key,
+ silc_rsa_set_private_key, silc_rsa_context_len,
+ silc_rsa_data_context_len, silc_rsa_set_arg,
+ silc_rsa_encrypt, silc_rsa_decrypt,
+ silc_rsa_sign, silc_rsa_verify },
+
+ { NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* Allocates a new SilcPKCS object. The new allocated object is returned
+ to the 'new_pkcs' argument. This function also initializes the data
+ context structure. Function returns 1 on success and 0 on error.
+
+*/
+int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
+{
+ int i;
+
+ SILC_LOG_DEBUG(("Allocating new PKCS object"));
+
+ for (i = 0; silc_pkcs_list[i].name; i++) {
+ if (!strcmp(silc_pkcs_list[i].name, name))
+ break;
+ }
+
+ if (silc_pkcs_list[i].name == NULL)
+ return FALSE;
+
+ *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
+ if (*new_pkcs == NULL) {
+ SILC_LOG_ERROR(("Could not allocate new PKCS object"));
+ return FALSE;
+ }
+
+ /* Set the pointers */
+ (*new_pkcs)->pkcs = &silc_pkcs_list[i];
+ (*new_pkcs)->pkcs->data_context =
+ silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
+ (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
+ (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
+
+ return TRUE;
+}
+
+/* Free's the PKCS object */
+
+void silc_pkcs_free(SilcPKCS pkcs)
+{
+ if (pkcs)
+ silc_free(pkcs->context);
+}
+
+/* Return TRUE if PKCS algorithm `name' is supported. */
+
+int silc_pkcs_is_supported(const unsigned char *name)
+{
+ int i;
+
+ for (i = 0; silc_pkcs_list[i].name; i++) {
+ if (!strcmp(silc_pkcs_list[i].name, name))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Returns comma separated list of supported PKCS algorithms */
+
+char *silc_pkcs_get_supported()
+{
+ char *list = NULL;
+ int i, len;
+
+ len = 0;
+ for (i = 0; silc_pkcs_list[i].name; i++) {
+ len += strlen(silc_pkcs_list[i].name);
+ list = silc_realloc(list, len + 1);
+
+ memcpy(list + (len - strlen(silc_pkcs_list[i].name)),
+ silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
+ memcpy(list + len, ",", 1);
+ len++;
+ }
+
+ list[len - 1] = 0;
+
+ return list;
+}
+
+/* Returns the length of the key */
+
+unsigned int silc_pkcs_get_key_len(SilcPKCS self)
+{
+ return self->key_len;
+}
+
+/* Returns SILC style public key */
+
+unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
+{
+ return pkcs->pkcs->get_public_key(pkcs->context, len);
+}
+
+/* Returns SILC style private key */
+
+unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
+{
+ return pkcs->pkcs->get_private_key(pkcs->context, len);
+}
+
+/* Sets public key */
+/* XXX rewrite */
+
+int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk,
+ unsigned int pk_len)
+{
+ return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
+}
+
+/* Sets private key */
+
+int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv,
+ unsigned int prv_len)
+{
+ return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
+}
+
+/* Saves public key into file */
+
+int silc_pkcs_save_public_key(SilcPKCS pkcs, char *filename,
+ unsigned char *pk, unsigned int pk_len)
+{
+ SilcBuffer buf;
+ int ret = TRUE;
+
+ buf = silc_buffer_alloc(strlen(pkcs->pkcs->name) + 2 + pk_len
+ + strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN)
+ + strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
+ SILC_STR_UI32_STRING(pkcs->pkcs->name),
+ SILC_STR_UI_SHORT(pk_len),
+ SILC_STR_UI_XNSTRING(pk, pk_len),
+ SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
+ SILC_STR_END);
+
+ /* Save into a file */
+ if (silc_file_write(filename, buf->data, buf->len)) {
+ ret = FALSE;
+ goto out;
+ }
+
+ out:
+ silc_buffer_free(buf);
+ return ret;
+}
+
+/* XXX The buffer should be encrypted */
+/* XXX rewrite */
+
+int silc_pkcs_save_private_key(SilcPKCS pkcs, char *filename,
+ unsigned char *prv, unsigned int prv_len,
+ char *passphrase)
+{
+ SilcBuffer buf;
+ int ret = TRUE;
+
+ buf = silc_buffer_alloc(strlen(pkcs->pkcs->name) + 2 + prv_len
+ + strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN)
+ + strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
+ SILC_STR_UI32_STRING(pkcs->pkcs->name),
+ SILC_STR_UI_SHORT(prv_len),
+ SILC_STR_UI_XNSTRING(prv, prv_len),
+ SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
+ SILC_STR_END);
+
+ /* Save into a file */
+ if (silc_file_write(filename, buf->data, buf->len)) {
+ ret = FALSE;
+ goto out;
+ }
+
+ out:
+ silc_buffer_free(buf);
+ return ret;
+}
+
+/* Loads public key from file and allocates new PKCS object and
+ sets the loaded key into it. */
+
+int silc_pkcs_load_public_key(char *filename, SilcPKCS *ret_pkcs)
+{
+
+ return TRUE;
+}
+
+/* Loads private key from file and allocates new PKCS object and
+ sets the loaded key into it. */
+
+int silc_pkcs_load_private_key(char *filename, SilcPKCS *ret_pkcs)
+{
+
+ return TRUE;
+}
--- /dev/null
+/*
+
+ silcpkcs.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPKCS_H
+#define SILCPKCS_H
+
+/* The default SILC PKCS (Public Key Cryptosystem) object to represent
+ any PKCS in SILC. */
+typedef struct SilcPKCSObjectStruct {
+ unsigned char *name;
+ void *data_context;
+
+ int (*init)(void *, unsigned int, SilcRng);
+ void (*clear_keys)(void *);
+ unsigned char *(*get_public_key)(void *, unsigned int *);
+ unsigned char *(*get_private_key)(void *, unsigned int *);
+ int (*set_public_key)(void *, unsigned char *, unsigned int);
+ int (*set_private_key)(void *, unsigned char *, unsigned int);
+ unsigned int (*context_len)();
+ unsigned int (*data_context_len)();
+ int (*set_arg)(void *, void *, int, SilcInt);
+ int (*encrypt)(void *, unsigned char *, unsigned int,
+ unsigned char *, unsigned int *);
+ int (*decrypt)(void *, unsigned char *, unsigned int,
+ unsigned char *, unsigned int *);
+ int (*sign)(void *, unsigned char *, unsigned int,
+ unsigned char *, unsigned int *);
+ int (*verify)(void *, unsigned char *, unsigned int,
+ unsigned char *, unsigned int);
+} SilcPKCSObject;
+
+/* The main SILC PKCS structure. Use SilcPKCS instead of SilcPKCSStruct.
+ Also remember that SilcPKCS is a pointer. */
+typedef struct SilcPKCSStruct {
+ void *context;
+ SilcPKCSObject *pkcs;
+ unsigned int key_len;
+
+ unsigned int (*get_key_len)(struct SilcPKCSStruct *);
+} *SilcPKCS;
+
+/* List of all PKCS in SILC. */
+extern SilcPKCSObject silc_pkcs_list[];
+
+/* Public and private key file headers */
+#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n"
+
+/* Macros */
+
+/* Macros used to implement the SILC PKCS API */
+
+/* XXX: This needs slight redesigning. These needs to be made even
+ more generic. I don't like that the actual prime generation is done
+ in PKCS_API_INIT. The primes used in key generation should be sent
+ as argument to the init function. By doing this we would achieve
+ that PKCS could be used as SIM's. The only requirement would be
+ that they are compiled against GMP (well, actually even that would
+ not be a requirement, but the most generic case anyway). The new init
+ would look something like this:
+
+ #define SILC_PKCS_API_INIT(pkcs) \
+ inline int silc_##pkcs##_init(void *context, unsigned int keylen, \
+ void *p1, void *p2)
+
+ Now we wouldn't have to send the SilcRng object since the primes are
+ provided as arguments. To send them as void * they could actually be
+ used as in anyway for real (MP_INT (SilcInt) or even something else
+ (the pointer could be kludged to be something else in the module))
+ (Plus, the SilcRng object management in prime generation would be
+ simpler and better what it is now (in silcprimegen.c, that is)).
+*/
+
+#define SILC_PKCS_API_INIT(pkcs) \
+int silc_##pkcs##_init(void *context, unsigned int keylen, \
+ SilcRng rng)
+#define SILC_PKCS_API_CLEAR_KEYS(pkcs) \
+void silc_##pkcs##_clear_keys(void *context)
+#define SILC_PKCS_API_GET_PUBLIC_KEY(pkcs) \
+unsigned char *silc_##pkcs##_get_public_key(void *context, \
+ unsigned int *ret_len)
+#define SILC_PKCS_API_GET_PRIVATE_KEY(pkcs) \
+unsigned char *silc_##pkcs##_get_private_key(void *context, \
+ unsigned int *ret_len)
+#define SILC_PKCS_API_SET_PUBLIC_KEY(pkcs) \
+int silc_##pkcs##_set_public_key(void *context, unsigned char *key_data, \
+ unsigned int key_len)
+#define SILC_PKCS_API_SET_PRIVATE_KEY(pkcs) \
+int silc_##pkcs##_set_private_key(void *context, unsigned char *key_data, \
+ unsigned int key_len)
+#define SILC_PKCS_API_CONTEXT_LEN(pkcs) \
+unsigned int silc_##pkcs##_context_len()
+#define SILC_PKCS_API_DATA_CONTEXT_LEN(pkcs) \
+unsigned int silc_##pkcs##_data_context_len()
+#define SILC_PKCS_API_SET_ARG(pkcs) \
+int silc_##pkcs##_set_arg(void *context, \
+ void *data_context, \
+ int argnum, \
+ SilcInt val)
+#define SILC_PKCS_API_ENCRYPT(pkcs) \
+int silc_##pkcs##_encrypt(void *context, \
+ unsigned char *src, \
+ unsigned int src_len, \
+ unsigned char *dst, \
+ unsigned int *dst_len)
+#define SILC_PKCS_API_DECRYPT(pkcs) \
+int silc_##pkcs##_decrypt(void *context, \
+ unsigned char *src, \
+ unsigned int src_len, \
+ unsigned char *dst, \
+ unsigned int *dst_len)
+#define SILC_PKCS_API_SIGN(pkcs) \
+int silc_##pkcs##_sign(void *context, \
+ unsigned char *src, \
+ unsigned int src_len, \
+ unsigned char *dst, \
+ unsigned int *dst_len)
+#define SILC_PKCS_API_VERIFY(pkcs) \
+int silc_##pkcs##_verify(void *context, \
+ unsigned char *signature, \
+ unsigned int signature_len, \
+ unsigned char *data, \
+ unsigned int data_len)
+
+/* Prototypes */
+int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs);
+void silc_pkcs_free(SilcPKCS pkcs);
+int silc_pkcs_is_supported(const unsigned char *name);
+char *silc_pkcs_get_supported();
+unsigned int silc_pkcs_get_key_len(SilcPKCS self);
+unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len);
+unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len);
+int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk,
+ unsigned int pk_len);
+int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv,
+ unsigned int prv_len);
+int silc_pkcs_save_public_key(SilcPKCS pkcs, char *filename,
+ unsigned char *pk, unsigned int pk_len);
+int silc_pkcs_save_private_key(SilcPKCS pkcs, char *filename,
+ unsigned char *prv, unsigned int prv_len,
+ char *passphrase);
+int silc_pkcs_load_public_key(char *filename, SilcPKCS *ret_pkcs);
+int silc_pkcs_load_private_key(char *filename, SilcPKCS *ret_pkcs);
+
+#endif
--- /dev/null
+/*
+
+ silcrng.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Created: Sun Mar 9 00:09:18 1997
+ *
+ * This RNG is based on Secure Shell's random number generator.
+ */
+/* XXX: Some operations block resulting slow initialization.
+ * XXX: I have some pending changes to make this better. */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#undef SILC_RNG_DEBUG
+/* #define SILC_RNG_DEBUG */
+
+/*
+ SILC SilcRng State context.
+
+ This object is used by the random number generator to provide
+ variable points where the actual random number is fetched from
+ the random pool. This provides that the data is not fetched always
+ from the same point of the pool. Short description of the fields
+ following.
+
+ unsigned int low
+ unsigned int pos
+
+ The index for the random pool buffer. Lowest and current
+ positions.
+
+ SilcRngStateContext *next
+
+ Pointer to the next state. If this is the last state this
+ will point to the first state thus providing circular list.
+
+*/
+typedef struct SilcRngStateContext {
+ unsigned int low;
+ unsigned int pos;
+ struct SilcRngStateContext *next;
+} *SilcRngState;
+
+/*
+ SILC Random Number Generator object.
+
+ This object holds random pool which is used to generate the random
+ numbers used by various routines needing cryptographically strong
+ random numbers. Following short descriptions of the fields.
+
+ unsigned char pool[]
+
+ The random pool. This buffer holds the random data. This is
+ frequently stirred thus providing ever changing randomnes.
+
+ unsigned char key[64]
+
+ Key used in stirring the random pool. The pool is encrypted
+ with SHA1 hash function in CFB (Cipher Feedback) mode.
+
+ SilcSilcRngState state
+
+ State object that is used to get the next position for the
+ random pool. This position is used to fetch data from pool
+ or to save the data to the pool. The state changes everytime
+ SilcRng is used.
+
+ SilcHash sha1
+
+ Hash object (SHA1) used to make the CFB encryption to the
+ random pool. This is allocated when RNG object is allocated and
+ free'd when RNG object is free'd.
+
+*/
+typedef struct SilcRngObjectStruct {
+ unsigned char pool[SILC_RNG_POOLSIZE];
+ unsigned char key[64];
+ SilcRngState state;
+ SilcHash sha1;
+} SilcRngObject;
+
+/* Allocates new RNG object. */
+
+SilcRng silc_rng_alloc()
+{
+ SilcRng new;
+
+ SILC_LOG_DEBUG(("Allocating new RNG object"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new RNG object"));
+ return NULL;
+ }
+
+ memset(new->pool, 0, sizeof(new->pool));
+ memset(new->key, 0, sizeof(new->key));
+ new->state = NULL;
+ silc_hash_alloc("sha1", &new->sha1);
+
+ return new;
+}
+
+/* Free's RNG object. */
+
+void silc_rng_free(SilcRng rng)
+{
+ if (rng) {
+ memset(rng->pool, 0, sizeof(rng->pool));
+ memset(rng->key, 0, sizeof(rng->key));
+ silc_free(rng->sha1);
+ silc_free(rng);
+ }
+}
+
+/* Initializes random number generator by getting noise from environment.
+ The environmental noise is our so called seed. One should not call
+ this function more than once. */
+
+void silc_rng_init(SilcRng rng)
+{
+ int i;
+ SilcRngState first, next;
+
+ assert(rng != NULL);
+
+ SILC_LOG_DEBUG(("Initializing RNG object"));
+
+ /* Initialize the states for the RNG. */
+ rng->state = silc_malloc(sizeof(*rng->state));
+ rng->state->low = 0;
+ rng->state->pos = 8;
+ rng->state->next = NULL;
+ first = rng->state;
+ for (i = SILC_RNG_STATE_NUM - 1; i >= 1; i--) {
+ next = silc_malloc(sizeof(*rng->state));
+ next->low =
+ (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM));
+ next->pos =
+ (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)) + 8;
+#if 0
+ next->pos = sizeof(rng->pool) -
+ ((i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM))) + 8;
+#endif
+ next->next = rng->state;
+ rng->state = next;
+ }
+ first->next = next;
+ rng->state = first;
+
+ memset(rng->pool, 0, sizeof(rng->pool));
+
+ /* Get noise from various environmental sources */
+ silc_rng_get_soft_noise(rng);
+ silc_rng_get_medium_noise(rng);
+ silc_rng_get_hard_noise(rng);
+}
+
+/* This function gets 'soft' noise from environment. */
+
+void silc_rng_get_soft_noise(SilcRng rng)
+{
+ struct tms ptime;
+
+ silc_rng_xor(rng, clock(), 0);
+ silc_rng_xor(rng, getpid(), 1);
+ silc_rng_xor(rng, getpgid(getpid() << 8), 2);
+ silc_rng_xor(rng, getpgid(getpid() << 8), 3);
+ silc_rng_xor(rng, getgid(), 4);
+ silc_rng_xor(rng, getpgrp(), 5);
+ silc_rng_xor(rng, getsid(getpid() << 16), 6);
+ silc_rng_xor(rng, times(&ptime), 7);
+ silc_rng_xor(rng, ptime.tms_utime, 8);
+ silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 9);
+ silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), 10);
+ silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 11);
+ silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), 12);
+ silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), 13);
+ silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), 14);
+ silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), 15);
+ silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), 16);
+ silc_rng_xor(rng, (ptime.tms_stime << 8), 17);
+ silc_rng_xor(rng, clock() << 4, 18);
+ silc_rng_xor(rng, getpgid(getpid() << 8), 19);
+ silc_rng_xor(rng, getpgrp(), 20);
+ silc_rng_xor(rng, getsid(getpid() << 16), 21);
+ silc_rng_xor(rng, times(&ptime), 22);
+ silc_rng_xor(rng, ptime.tms_utime, 23);
+ silc_rng_xor(rng, getpgrp(), 24);
+
+ /* Stir random pool */
+ silc_rng_stir_pool(rng);
+}
+
+/* This function gets noise from different commands */
+
+void silc_rng_get_medium_noise(SilcRng rng)
+{
+ silc_rng_exec_command(rng, "ps -lefaww 2> /dev/null");
+ silc_rng_exec_command(rng, "ls -afiln 2> /dev/null");
+ silc_rng_exec_command(rng, "ps -asww 2> /dev/null");
+ silc_rng_exec_command(rng, "ls -afiln /proc 2> /dev/null");
+ /*
+ silc_rng_exec_command(rng, "ps -ef 2> /dev/null");
+ silc_rng_exec_command(rng, "ls -alin /dev 2> /dev/null");
+ */
+}
+
+/* This function gets 'hard' noise from environment. This tries to
+ get the noise from /dev/random if available. */
+
+void silc_rng_get_hard_noise(SilcRng rng)
+{
+ char buf[32];
+ int fd, len, i;
+
+ /* Get noise from /dev/random if available */
+ fd = open("/dev/random", O_RDONLY);
+ if (fd < 0)
+ return;
+
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ for (i = 0; i < 8; i++) {
+ len = read(fd, buf, sizeof(buf));
+ if (len <= 0)
+ goto out;
+ silc_rng_add_noise(rng, buf, len);
+ }
+
+ out:
+ close(fd);
+ memset(buf, 0, sizeof(buf));
+}
+
+/* Execs command and gets noise from its output */
+
+void silc_rng_exec_command(SilcRng rng, char *command)
+{
+ char buf[2048];
+ FILE *fd;
+ int i;
+ int c;
+
+ /* Open process */
+ fd = popen(command, "r");
+ if (!fd)
+ return;
+
+ /* Get data as much as we can get into the buffer */
+ for (i = 0; i < sizeof(buf); i++) {
+ c = fgetc(fd);
+ if (c == EOF) {
+ if (!i)
+ return;
+ break;
+ }
+ buf[i] = c;
+ }
+
+ pclose(fd);
+
+ /* Add the buffer into random pool */
+ silc_rng_add_noise(rng, buf, strlen(buf));
+ memset(buf, 0, sizeof(buf));
+}
+
+/* This function adds the contents of the buffer as noise into random
+ pool. After adding the noise the pool is stirred. */
+
+void silc_rng_add_noise(SilcRng rng, unsigned char *buffer,
+ unsigned int len)
+{
+ unsigned int i, pos;
+
+ pos = silc_rng_get_position(rng);
+
+ /* Add the buffer one by one into the pool */
+ for(i = 0; i < len; i++, buffer++) {
+ if(pos >= SILC_RNG_POOLSIZE)
+ break;
+ rng->pool[pos++] ^= *buffer;
+ }
+
+ /* Stir random pool */
+ silc_rng_stir_pool(rng);
+}
+
+/* XOR's data into the pool */
+
+void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos)
+{
+ assert(rng != NULL);
+ rng->pool[pos] ^= val + val;
+}
+
+/* This function stirs the random pool by encrypting buffer in CFB
+ (cipher feedback) mode with SHA1 algorithm. */
+
+void silc_rng_stir_pool(SilcRng rng)
+{
+ int i;
+ unsigned long iv[5];
+
+ /* Get the IV */
+ memcpy(iv, &rng->pool[SILC_RNG_POOLSIZE - 256], sizeof(iv));
+
+ /* First CFB pass */
+ for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
+ rng->sha1->hash->transform(iv, rng->key);
+ iv[0] = rng->pool[i] ^= iv[0];
+ iv[1] = rng->pool[i + 1] ^= iv[1];
+ iv[2] = rng->pool[i + 2] ^= iv[2];
+ iv[3] = rng->pool[i + 3] ^= iv[3];
+ iv[4] = rng->pool[i + 4] ^= iv[4];
+ }
+
+ /* Get new key */
+ memcpy(rng->key, &rng->pool[silc_rng_get_position(rng)], sizeof(rng->key));
+
+ /* Second CFB pass */
+ for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
+ rng->sha1->hash->transform(iv, rng->key);
+ iv[0] = rng->pool[i] ^= iv[0];
+ iv[1] = rng->pool[i + 1] ^= iv[1];
+ iv[2] = rng->pool[i + 2] ^= iv[2];
+ iv[3] = rng->pool[i + 3] ^= iv[3];
+ iv[4] = rng->pool[i + 4] ^= iv[4];
+ }
+
+ memset(iv, 0, sizeof(iv));
+}
+
+/* Returns next position where data is fetched from the pool or
+ put to the pool. */
+
+unsigned int silc_rng_get_position(SilcRng rng)
+{
+ SilcRngState next;
+ unsigned int pos;
+
+ next = rng->state->next;
+
+ pos = rng->state->pos++;
+ if ((next->low != 0 && pos >= next->low) || (pos >= SILC_RNG_POOLSIZE))
+ rng->state->pos = rng->state->low;
+
+#ifdef SILC_RNG_DEBUG
+ fprintf(stderr, "state: %p: low: %d, pos: %d\n",
+ rng->state, rng->state->low, rng->state->pos);
+#endif
+
+ rng->state = next;
+
+ return pos;
+}
+
+/* returns random byte. Every two byte is from pools low or high state. */
+
+unsigned char silc_rng_get_byte(SilcRng rng)
+{
+ return rng->pool[silc_rng_get_position(rng)];
+}
+
+/* Returns 16 bit random number */
+
+unsigned short silc_rng_get_rn16(SilcRng rng)
+{
+ unsigned char rn[2];
+ unsigned short num;
+
+ rn[0] = silc_rng_get_byte(rng);
+ rn[1] = silc_rng_get_byte(rng);
+ SILC_GET16_MSB(num, rn);
+
+ return num;
+}
+
+/* Returns 32 bit random number */
+
+unsigned int silc_rng_get_rn32(SilcRng rng)
+{
+ unsigned char rn[4];
+ unsigned short num;
+
+ rn[0] = silc_rng_get_byte(rng);
+ rn[1] = silc_rng_get_byte(rng);
+ rn[2] = silc_rng_get_byte(rng);
+ rn[3] = silc_rng_get_byte(rng);
+ SILC_GET32_MSB(num, rn);
+
+ return num;
+}
+
+/* Returns random number string. Returned string is in HEX format. */
+
+unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len)
+{
+ int i;
+ unsigned char *string;
+
+ string = silc_calloc((len * 2 + 1), sizeof(unsigned char));
+ if (string == NULL)
+ return NULL;
+
+ for (i = 0; i < len; i++)
+ sprintf(string + 2 * i, "%02x", silc_rng_get_byte(rng));
+
+ return string;
+}
--- /dev/null
+/*
+
+ silcSilcRng.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCRNG_H
+#define SILCRNG_H
+
+/* Forward declaration. Actual object is in source file. */
+typedef struct SilcRngObjectStruct *SilcRng;
+
+/* Number of states to fetch data from pool. */
+#define SILC_RNG_STATE_NUM 4
+
+/* Byte size of the random data pool. */
+#define SILC_RNG_POOLSIZE 1024
+
+/* Prototypes */
+SilcRng silc_rng_alloc();
+void silc_rng_free(SilcRng rng);
+void silc_rng_init(SilcRng rng);
+void silc_rng_get_soft_noise(SilcRng rng);
+void silc_rng_get_medium_noise(SilcRng rng);
+void silc_rng_get_hard_noise(SilcRng rng);
+void silc_rng_exec_command(SilcRng rng, char *command);
+void silc_rng_add_noise(SilcRng rng, unsigned char *buffer,
+ unsigned int len);
+void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos);
+void silc_rng_stir_pool(SilcRng rng);
+unsigned int silc_rng_get_position(SilcRng rng);
+unsigned char silc_rng_get_byte(SilcRng rng);
+unsigned short silc_rng_get_rn16(SilcRng rng);
+unsigned int silc_rng_get_rn32(SilcRng rng);
+unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len);
+
+#endif
--- /dev/null
+gcc -I.. \
+-I../../../includes -I../../silccore \
+-I../.. -I../../silccore -I../../silcmath \
+-I../../silcmath/gmp-2.0.2 -I../../silcske -I../../silcsim \
+-Wall -finline-functions \
+-o test_rsa test_rsa.c -L../.. -lsilc
+
--- /dev/null
+gcc -I.. \
+-I../../../includes -I../../silccore \
+-I../.. -I../../silccore -I../../silcmath \
+-I../../silcmath/gmp-2.0.2 -I../../silcske -I../../silcsim \
+-Wall -finline-functions \
+-o test_rsa test_rsa.c -L../.. -lsilc
+
--- /dev/null
+gcc -I.. \
+-I../../../includes -I../../silccore \
+-I../.. -I../../silccore -I../../silcmath \
+-I../../silcmath/gmp-2.0.2 -I../../silcske -I../../silcsim \
+-Wall -finline-functions \
+-o test_twofish test_twofish.c -L../.. -lsilc
+
--- /dev/null
+gcc -I../
+-I../../../includes -I../../silccore \
+-I../
+-Wall -finline-functions
+-o test_rsa test_rsa.c -L../.. -lsilc
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mars.h"
+
+int main()
+{
+ int i;
+ unsigned char key[256];
+ unsigned char plain[256];
+ unsigned char plain2[256];
+ unsigned char cipher[256];
+ unsigned char iv[256];
+
+ memset(&key, 0, sizeof(key));
+ memset(&plain, 0, sizeof(plain));
+ memset(&plain2, 0, sizeof(plain2));
+ memset(&cipher, 0, sizeof(cipher));
+ memset(&iv, 0, sizeof(iv));
+
+ fprintf(stderr, "\nKey:\n");
+ for (i = 0; i < (sizeof(key) / 2); i += 2) {
+ fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
+ }
+
+ fprintf(stderr, "\nSetting key\n");
+ silc_mars_init(NULL, key, 128);
+
+ fprintf(stderr, "\nPlaintext:\n");
+ for (i = 0; i < (sizeof(plain) / 2); i += 2) {
+ plain[i] = i;
+ plain[i+1] = i+1;
+ fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+ }
+
+ fprintf(stderr, "\n\nEncrypting\n");
+ silc_mars_encrypt_cbc(NULL, plain, cipher, 256, iv);
+
+ fprintf(stderr, "Ciphertext:\n");
+ for (i = 0; i < (sizeof(cipher)/2); i += 2) {
+ fprintf(stderr, "%02x", cipher[i]);
+ fprintf(stderr, "%02x ", cipher[i+1]);
+ }
+
+ fprintf(stderr, "\n\nDecrypting\n");
+ silc_mars_decrypt_cbc(NULL, cipher, plain2, 256, iv);
+
+ fprintf(stderr, "Decryptedtext:\n");
+ for (i = 0; i < (sizeof(plain2)/2); i += 2) {
+ fprintf(stderr, "%02x", plain2[i]);
+ fprintf(stderr, "%02x ", plain2[i+1]);
+ }
+ fprintf(stderr, "\nDone\n");
+
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+main()
+{
+ int i, k;
+ unsigned char key[256];
+ unsigned char plain[256];
+ unsigned char plain2[256];
+ unsigned char cipher[256];
+ memset(&key, 0, sizeof(key));
+ memset(&plain, 0, sizeof(plain));
+ memset(&plain2, 0, sizeof(plain2));
+ memset(&cipher, 0, sizeof(cipher));
+
+ fprintf(stderr, "\nKey:\n");
+ for (i = 0; i < sizeof(key) / 2; i++) {
+ key[i] = i;
+ key[i+1] = i+1;
+ fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
+ }
+
+ fprintf(stderr, "\nSetting key\n");
+ set_key(key, 128);
+
+ fprintf(stderr, "\nPlaintext:\n");
+ for (i = 0; i < sizeof(plain) / 2; i++) {
+ plain[i] = i;
+ plain[i+1] = i+1;
+ fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+ }
+
+ fprintf(stderr, "Encrypting\n");
+ encrypt(plain, cipher);
+
+ fprintf(stderr, "\nCiphertext:\n");
+ for (i = 0; i < sizeof(cipher); i++) {
+ fprintf(stderr, "%02x", cipher[i]);
+ }
+
+ fprintf(stderr, "Decrypting\n");
+ decrypt(cipher, plain2);
+
+ fprintf(stderr, "\nDecryptedtext:\n");
+ for (i = 0; i < sizeof(plain2); i++) {
+ fprintf(stderr, "%02x", plain2[i]);
+ }
+
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "silcincludes.h"
+#include "rsa.h"
+#include "rsa_internal.h"
+
+void testi(SilcRng rng, void *context)
+{
+ char *numbuf;
+ unsigned int bytes;
+ unsigned int i;
+ MP_INT tnum; /* number we'll encrypt */
+ MP_INT test; /* en/decrypted result of tnum */
+ RsaKey *key = (RsaKey *)context;
+ int bits = 1024;
+
+ numbuf = (char *)malloc((bits / 3) + 1);
+ bytes = bits / 10;
+
+ mpz_init(&tnum);
+ mpz_init(&test);
+
+ fprintf(stderr, "\nTesting encryption and decryption ... ");
+
+ for(i = 0; i < bytes; i++)
+ sprintf(numbuf + 2 * i, "%02x", silc_rng_get_byte(rng));
+
+ mpz_set_str(&tnum, numbuf, 16);
+
+ /* empty buffer */
+ memset(numbuf, 0, bits / 3);
+ free(numbuf);
+
+ /* make tnum smaller than n */
+ mpz_div_ui(&tnum, &tnum, 10);
+ /* encrypt */
+ rsa_en_de_crypt(&test, &tnum, &key->e, &key->n);
+ /* decrypt */
+ rsa_en_de_crypt(&test, &test, &key->d, &key->n);
+ /* see if decrypted result is same than the original one is */
+ if (mpz_cmp(&test, &tnum) != 0) {
+ fprintf(stderr, "Error in encryption and decryption!\n");
+ return -1;
+ }
+
+ mpz_clear(&tnum);
+ mpz_clear(&test);
+
+ fprintf(stderr, "Keys are Ok.\n");
+}
+
+int main()
+{
+ SilcPKCS pkcs;
+ SilcRng rng;
+ unsigned char *pk, *prv;
+ unsigned int pk_len, prv_len;
+ unsigned char *src, *dst, *new;
+ unsigned int src_len, dst_len, new_len;
+ SilcInt tnum, test;
+
+ silc_pkcs_alloc("rsa", &pkcs);
+
+ rng = silc_rng_alloc();
+ silc_rng_init(rng);
+ silc_math_primegen_init();
+
+ pkcs->pkcs->init(pkcs->context, 1024, rng);
+
+ pk = silc_pkcs_get_public_key(pkcs, &pk_len);
+ prv = silc_pkcs_get_public_key(pkcs, &prv_len);
+
+ src = "PEKKA RIIKONEN";
+ src_len = 5;
+ dst = silc_calloc(200, sizeof(unsigned char));
+ pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, &dst_len);
+
+ SILC_LOG_HEXDUMP(("src"), src, src_len);
+ SILC_LOG_HEXDUMP(("dst"), dst, dst_len);
+
+ new = silc_calloc(200, sizeof(unsigned char));
+ pkcs->pkcs->decrypt(pkcs->context, dst, dst_len, new, &new_len);
+
+ SILC_LOG_HEXDUMP(("new"), new, new_len);
+
+ testi(rng, pkcs->context);
+
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+//#include "../ciphers.h"
+#include "../serpent.h"
+
+#define timediff(tv2, tv1) (((tv2)->tv_sec - (tv1)->tv_sec)*1000000 + \
+ ((tv2)->tv_usec - (tv1)->tv_usec))
+
+int main(int argc, char **argv)
+{
+ int i;
+ unsigned char key[256];
+ unsigned char plain[512];
+ unsigned char plain2[512];
+ unsigned char cipher[512];
+ unsigned char iv[128];
+ struct timeval tv1,tv2;
+
+ memset(&key, 0, sizeof(key));
+ memset(&plain, 0, sizeof(plain));
+ memset(&plain2, 0, sizeof(plain2));
+ memset(&cipher, 0, sizeof(cipher));
+ memset(&iv, 0, sizeof(iv));
+
+ gettimeofday(&tv1, NULL);
+ silc_serpent_init(NULL, key, 128);
+ gettimeofday(&tv2, NULL);
+
+ fprintf(stderr, "\nPlaintext:\n");
+ for (i = 0; i < sizeof(plain) / 2; i += 2) {
+ plain[i] = i;
+ plain[i+1] = i+1;
+ fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+ }
+
+ fprintf(stderr, "\n\nEncrypting\n");
+ gettimeofday(&tv1, NULL);
+ silc_serpent_encrypt_cbc(NULL, plain, cipher, sizeof(plain), iv);
+ gettimeofday(&tv2, NULL);
+
+ fprintf(stderr, "Encrypt %6.3f Mb/s\n",
+ 1000000.0*8.0/timediff(&tv2,&tv1));
+
+ fprintf(stderr, "Ciphertext:\n");
+ for (i = 0; i < (sizeof(cipher)/2); i += 2) {
+ fprintf(stderr, "%02x", cipher[i]);
+ fprintf(stderr, "%02x ", cipher[i+1]);
+ }
+
+ fprintf(stderr, "\n\nDecrypting\n");
+ gettimeofday(&tv1, NULL);
+ silc_serpent_decrypt_cbc(NULL, cipher, plain2, sizeof(cipher), iv);
+ gettimeofday(&tv2, NULL);
+
+ fprintf(stderr, "Decrypt %6.3f Mb/s\n",
+ 1000000.0*8.0/timediff(&tv2,&tv1));
+
+ fprintf(stderr, "Decrypted text:\n");
+ for (i = 0; i < (sizeof(plain2)/2); i += 2) {
+ fprintf(stderr, "%02x", plain2[i]);
+ fprintf(stderr, "%02x ", plain2[i+1]);
+ }
+ fprintf(stderr, "\nDone\n");
+
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ int i, k, l;
+ unsigned char key[256];
+ unsigned char plain[256];
+ unsigned char plain2[256];
+ unsigned char cipher[256];
+ memset(&key, 0, sizeof(key));
+ memset(&plain, 0, sizeof(plain));
+ memset(&plain2, 0, sizeof(plain2));
+ memset(&cipher, 0, sizeof(cipher));
+
+ fprintf(stderr, "\nKey:\n");
+ for (i = 0; i < (sizeof(plain) / 2); i++) {
+ key[i] = i;
+ key[i+1] = i+1;
+ fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
+ }
+
+ fprintf(stderr, "\nSetting key\n");
+ set_key(key, 128);
+
+ fprintf(stderr, "\nPlaintext:\n");
+ for (i = 0; i < (sizeof(plain) / 2); i++) {
+ plain[i] = i;
+ plain[i+1] = i+1;
+ fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+ }
+
+ fprintf(stderr, "\n\nEncrypting\n");
+ fprintf(stderr, "Ciphertext:\n");
+ l = 0;
+ for (k = 0; k < 8; k++) {
+ encrypt(&plain[l], &cipher[l]);
+ for (i = 0; i < 16; i++) {
+ fprintf(stderr, "%02x", cipher[l+i]);
+ fprintf(stderr, "%02x ", cipher[l+i+1]);
+ }
+ l += 16;
+ }
+
+ fprintf(stderr, "\n\nDecrypting\n");
+
+ fprintf(stderr, "Decryptedtext:\n");
+ l = 0;
+ for (k = 0; k < 8; k++) {
+ decrypt(&cipher[l], &plain2[l]);
+ for (i = 0; i < 16; i++) {
+ fprintf(stderr, "%02x", plain2[l+i]);
+ fprintf(stderr, "%02x ", plain2[l+i+1]);
+ }
+ l += 16;
+ }
+ fprintf(stderr, "\nAll done.\n");
+
+ return 0;
+}
--- /dev/null
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm: */
+/* */
+/* Twofish by Bruce Schneier and colleagues */
+/* */
+/* which is a candidate algorithm in the Advanced Encryption Standard */
+/* programme of the US National Institute of Standards and Technology. */
+/* */
+/* Copyright in this implementation is held by Dr B R Gladman but I */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions */
+/* that the originators of t he algorithm place on its exploitation. */
+/* */
+/* My thanks to Doug Whiting and Niels Ferguson for comments that led */
+/* to improvements in this implementation. */
+/* */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
+
+/* Timing data for Twofish (twofish.c)
+
+128 bit key:
+Key Setup: 8414 cycles
+Encrypt: 376 cycles = 68.1 mbits/sec
+Decrypt: 374 cycles = 68.4 mbits/sec
+Mean: 375 cycles = 68.3 mbits/sec
+
+192 bit key:
+Key Setup: 11628 cycles
+Encrypt: 376 cycles = 68.1 mbits/sec
+Decrypt: 374 cycles = 68.4 mbits/sec
+Mean: 375 cycles = 68.3 mbits/sec
+
+256 bit key:
+Key Setup: 15457 cycles
+Encrypt: 381 cycles = 67.2 mbits/sec
+Decrypt: 374 cycles = 68.4 mbits/sec
+Mean: 378 cycles = 67.8 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "twofish.h"
+
+/*
+ * SILC Crypto API for Twofish
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(twofish)
+{
+ twofish_set_key((TwofishContext *)context, (unsigned int *)key, keylen);
+ return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(twofish)
+{
+ /* unsigned char key[md5_hash_len];
+ SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+ make_md5_hash(string, &key);
+ memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+ memset(&key, 'F', sizeoof(key));
+ */
+
+ return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(twofish)
+{
+ return sizeof(TwofishContext);
+}
+
+/* Encrypts with the cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(twofish)
+{
+ unsigned int *in, *out, *tiv;
+ unsigned int tmp[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0] ^ tiv[0];
+ tmp[1] = in[1] ^ tiv[1];
+ tmp[2] = in[2] ^ tiv[2];
+ tmp[3] = in[3] ^ tiv[3];
+ twofish_encrypt((TwofishContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp[0] = in[0] ^ out[0 - 4];
+ tmp[1] = in[1] ^ out[1 - 4];
+ tmp[2] = in[2] ^ out[2 - 4];
+ tmp[3] = in[3] ^ out[3 - 4];
+ twofish_encrypt((TwofishContext *)context, tmp, out);
+ in += 4;
+ out += 4;
+ }
+
+ tiv[0] = out[0 - 4];
+ tiv[1] = out[1 - 4];
+ tiv[2] = out[2 - 4];
+ tiv[3] = out[3 - 4];
+
+ return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(twofish)
+{
+ unsigned int *tiv, *in, *out;
+ unsigned int tmp[4], tmp2[4];
+ int i;
+
+ in = (unsigned int *)src;
+ out = (unsigned int *)dst;
+ tiv = (unsigned int *)iv;
+
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ twofish_decrypt((TwofishContext *)context, in, out);
+ out[0] ^= tiv[0];
+ out[1] ^= tiv[1];
+ out[2] ^= tiv[2];
+ out[3] ^= tiv[3];
+ in += 4;
+ out += 4;
+
+ for (i = 16; i < len; i += 16) {
+ tmp2[0] = tmp[0];
+ tmp2[1] = tmp[1];
+ tmp2[2] = tmp[2];
+ tmp2[3] = tmp[3];
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ twofish_decrypt((TwofishContext *)context, in, out);
+ out[0] ^= tmp2[0];
+ out[1] ^= tmp2[1];
+ out[2] ^= tmp2[2];
+ out[3] ^= tmp2[3];
+ in += 4;
+ out += 4;
+ }
+
+ tiv[0] = tmp[0];
+ tiv[1] = tmp[1];
+ tiv[2] = tmp[2];
+ tiv[3] = tmp[3];
+
+ return TRUE;
+}
+
+#if 0
+#define Q_TABLES
+#define M_TABLE
+#define MK_TABLE
+#define ONE_STEP
+#endif
+
+/* finite field arithmetic for GF(2**8) with the modular */
+/* polynomial x^8 + x^6 + x^5 + x^3 + 1 (0x169) */
+
+#define G_M 0x0169
+
+u1byte tab_5b[4] = { 0, G_M >> 2, G_M >> 1, (G_M >> 1) ^ (G_M >> 2) };
+u1byte tab_ef[4] = { 0, (G_M >> 1) ^ (G_M >> 2), G_M >> 1, G_M >> 2 };
+
+#define ffm_01(x) (x)
+#define ffm_5b(x) ((x) ^ ((x) >> 2) ^ tab_5b[(x) & 3])
+#define ffm_ef(x) ((x) ^ ((x) >> 1) ^ ((x) >> 2) ^ tab_ef[(x) & 3])
+
+u1byte ror4[16] = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
+u1byte ashx[16] = { 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 };
+
+u1byte qt0[2][16] =
+{ { 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 },
+ { 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 }
+};
+
+u1byte qt1[2][16] =
+{ { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 },
+ { 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 }
+};
+
+u1byte qt2[2][16] =
+{ { 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 },
+ { 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 }
+};
+
+u1byte qt3[2][16] =
+{ { 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 },
+ { 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 }
+};
+
+u1byte qp(const u4byte n, const u1byte x)
+{ u1byte a0, a1, a2, a3, a4, b0, b1, b2, b3, b4;
+
+ a0 = x >> 4; b0 = x & 15;
+ a1 = a0 ^ b0; b1 = ror4[b0] ^ ashx[a0];
+ a2 = qt0[n][a1]; b2 = qt1[n][b1];
+ a3 = a2 ^ b2; b3 = ror4[b2] ^ ashx[a2];
+ a4 = qt2[n][a3]; b4 = qt3[n][b3];
+ return (b4 << 4) | a4;
+};
+
+#ifdef Q_TABLES
+
+u4byte qt_gen = 0;
+u1byte q_tab[2][256];
+
+#define q(n,x) q_tab[n][x]
+
+void gen_qtab(void)
+{ u4byte i;
+
+ for(i = 0; i < 256; ++i)
+ {
+ q(0,i) = qp(0, (u1byte)i);
+ q(1,i) = qp(1, (u1byte)i);
+ }
+};
+
+#else
+
+#define q(n,x) qp(n, x)
+
+#endif
+
+#ifdef M_TABLE
+
+u4byte mt_gen = 0;
+u4byte m_tab[4][256];
+
+void gen_mtab(void)
+{ u4byte i, f01, f5b, fef;
+
+ for(i = 0; i < 256; ++i)
+ {
+ f01 = q(1,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
+ m_tab[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
+ m_tab[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);
+
+ f01 = q(0,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
+ m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
+ m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
+ }
+};
+
+#define mds(n,x) m_tab[n][x]
+
+#else
+
+#define fm_00 ffm_01
+#define fm_10 ffm_5b
+#define fm_20 ffm_ef
+#define fm_30 ffm_ef
+#define q_0(x) q(1,x)
+
+#define fm_01 ffm_ef
+#define fm_11 ffm_ef
+#define fm_21 ffm_5b
+#define fm_31 ffm_01
+#define q_1(x) q(0,x)
+
+#define fm_02 ffm_5b
+#define fm_12 ffm_ef
+#define fm_22 ffm_01
+#define fm_32 ffm_ef
+#define q_2(x) q(1,x)
+
+#define fm_03 ffm_5b
+#define fm_13 ffm_01
+#define fm_23 ffm_ef
+#define fm_33 ffm_5b
+#define q_3(x) q(0,x)
+
+#define f_0(n,x) ((u4byte)fm_0##n(x))
+#define f_1(n,x) ((u4byte)fm_1##n(x) << 8)
+#define f_2(n,x) ((u4byte)fm_2##n(x) << 16)
+#define f_3(n,x) ((u4byte)fm_3##n(x) << 24)
+
+#define mds(n,x) f_0(n,q_##n(x)) ^ f_1(n,q_##n(x)) ^ f_2(n,q_##n(x)) ^ f_3(n,q_##n(x))
+
+#endif
+
+u4byte h_fun(TwofishContext *ctx, const u4byte x, const u4byte key[])
+{ u4byte b0, b1, b2, b3;
+
+#ifndef M_TABLE
+ u4byte m5b_b0, m5b_b1, m5b_b2, m5b_b3;
+ u4byte mef_b0, mef_b1, mef_b2, mef_b3;
+#endif
+
+ b0 = byte(x, 0); b1 = byte(x, 1); b2 = byte(x, 2); b3 = byte(x, 3);
+
+ switch(ctx->k_len)
+ {
+ case 4: b0 = q(1, b0) ^ byte(key[3],0);
+ b1 = q(0, b1) ^ byte(key[3],1);
+ b2 = q(0, b2) ^ byte(key[3],2);
+ b3 = q(1, b3) ^ byte(key[3],3);
+ case 3: b0 = q(1, b0) ^ byte(key[2],0);
+ b1 = q(1, b1) ^ byte(key[2],1);
+ b2 = q(0, b2) ^ byte(key[2],2);
+ b3 = q(0, b3) ^ byte(key[2],3);
+ case 2: b0 = q(0,q(0,b0) ^ byte(key[1],0)) ^ byte(key[0],0);
+ b1 = q(0,q(1,b1) ^ byte(key[1],1)) ^ byte(key[0],1);
+ b2 = q(1,q(0,b2) ^ byte(key[1],2)) ^ byte(key[0],2);
+ b3 = q(1,q(1,b3) ^ byte(key[1],3)) ^ byte(key[0],3);
+ }
+#ifdef M_TABLE
+
+ return mds(0, b0) ^ mds(1, b1) ^ mds(2, b2) ^ mds(3, b3);
+
+#else
+
+ b0 = q(1, b0); b1 = q(0, b1); b2 = q(1, b2); b3 = q(0, b3);
+ m5b_b0 = ffm_5b(b0); m5b_b1 = ffm_5b(b1); m5b_b2 = ffm_5b(b2); m5b_b3 = ffm_5b(b3);
+ mef_b0 = ffm_ef(b0); mef_b1 = ffm_ef(b1); mef_b2 = ffm_ef(b2); mef_b3 = ffm_ef(b3);
+ b0 ^= mef_b1 ^ m5b_b2 ^ m5b_b3; b3 ^= m5b_b0 ^ mef_b1 ^ mef_b2;
+ b2 ^= mef_b0 ^ m5b_b1 ^ mef_b3; b1 ^= mef_b0 ^ mef_b2 ^ m5b_b3;
+
+ return b0 | (b3 << 8) | (b2 << 16) | (b1 << 24);
+
+#endif
+};
+
+#ifdef MK_TABLE
+
+#ifdef ONE_STEP
+u4byte mk_tab[4][256];
+#else
+u1byte sb[4][256];
+#endif
+
+#define q20(x) q(0,q(0,x) ^ byte(key[1],0)) ^ byte(key[0],0)
+#define q21(x) q(0,q(1,x) ^ byte(key[1],1)) ^ byte(key[0],1)
+#define q22(x) q(1,q(0,x) ^ byte(key[1],2)) ^ byte(key[0],2)
+#define q23(x) q(1,q(1,x) ^ byte(key[1],3)) ^ byte(key[0],3)
+
+#define q30(x) q(0,q(0,q(1, x) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
+#define q31(x) q(0,q(1,q(1, x) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
+#define q32(x) q(1,q(0,q(0, x) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
+#define q33(x) q(1,q(1,q(0, x) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)
+
+#define q40(x) q(0,q(0,q(1, q(1, x) ^ byte(key[3],0)) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
+#define q41(x) q(0,q(1,q(1, q(0, x) ^ byte(key[3],1)) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
+#define q42(x) q(1,q(0,q(0, q(0, x) ^ byte(key[3],2)) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
+#define q43(x) q(1,q(1,q(0, q(1, x) ^ byte(key[3],3)) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)
+
+void gen_mk_tab(TwofishContext *ctx, u4byte key[])
+{ u4byte i;
+ u1byte by;
+
+ switch(ctx->k_len)
+ {
+ case 2: for(i = 0; i < 256; ++i)
+ {
+ by = (u1byte)i;
+#ifdef ONE_STEP
+ mk_tab[0][i] = mds(0, q20(by)); mk_tab[1][i] = mds(1, q21(by));
+ mk_tab[2][i] = mds(2, q22(by)); mk_tab[3][i] = mds(3, q23(by));
+#else
+ sb[0][i] = q20(by); sb[1][i] = q21(by);
+ sb[2][i] = q22(by); sb[3][i] = q23(by);
+#endif
+ }
+ break;
+
+ case 3: for(i = 0; i < 256; ++i)
+ {
+ by = (u1byte)i;
+#ifdef ONE_STEP
+ mk_tab[0][i] = mds(0, q30(by)); mk_tab[1][i] = mds(1, q31(by));
+ mk_tab[2][i] = mds(2, q32(by)); mk_tab[3][i] = mds(3, q33(by));
+#else
+ sb[0][i] = q30(by); sb[1][i] = q31(by);
+ sb[2][i] = q32(by); sb[3][i] = q33(by);
+#endif
+ }
+ break;
+
+ case 4: for(i = 0; i < 256; ++i)
+ {
+ by = (u1byte)i;
+#ifdef ONE_STEP
+ mk_tab[0][i] = mds(0, q40(by)); mk_tab[1][i] = mds(1, q41(by));
+ mk_tab[2][i] = mds(2, q42(by)); mk_tab[3][i] = mds(3, q43(by));
+#else
+ sb[0][i] = q40(by); sb[1][i] = q41(by);
+ sb[2][i] = q42(by); sb[3][i] = q43(by);
+#endif
+ }
+ }
+};
+
+# ifdef ONE_STEP
+# define g0_fun(x) ( mk_tab[0][byte(x,0)] ^ mk_tab[1][byte(x,1)] \
+ ^ mk_tab[2][byte(x,2)] ^ mk_tab[3][byte(x,3)] )
+# define g1_fun(x) ( mk_tab[0][byte(x,3)] ^ mk_tab[1][byte(x,0)] \
+ ^ mk_tab[2][byte(x,1)] ^ mk_tab[3][byte(x,2)] )
+# else
+# define g0_fun(x) ( mds(0, sb[0][byte(x,0)]) ^ mds(1, sb[1][byte(x,1)]) \
+ ^ mds(2, sb[2][byte(x,2)]) ^ mds(3, sb[3][byte(x,3)]) )
+# define g1_fun(x) ( mds(0, sb[0][byte(x,3)]) ^ mds(1, sb[1][byte(x,0)]) \
+ ^ mds(2, sb[2][byte(x,1)]) ^ mds(3, sb[3][byte(x,2)]) )
+# endif
+
+#else
+
+#define g0_fun(x) h_fun(ctx,x,s_key)
+#define g1_fun(x) h_fun(ctx,rotl(x,8),s_key)
+
+#endif
+
+/* The (12,8) Reed Soloman code has the generator polynomial
+
+ g(x) = x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1
+
+where the coefficients are in the finite field GF(2^8) with a
+modular polynomial a^8 + a^6 + a^3 + a^2 + 1. To generate the
+remainder we have to start with a 12th order polynomial with our
+eight input bytes as the coefficients of the 4th to 11th terms.
+That is:
+
+ m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0
+
+We then multiply the generator polynomial by m[7] * x^7 and subtract
+it - xor in GF(2^8) - from the above to eliminate the x^7 term (the
+artihmetic on the coefficients is done in GF(2^8). We then multiply
+the generator polynomial by x^6 * coeff(x^10) and use this to remove
+the x^10 term. We carry on in this way until the x^4 term is removed
+so that we are left with:
+
+ r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]
+
+which give the resulting 4 bytes of the remainder. This is equivalent
+to the matrix multiplication in the Twofish description but much faster
+to implement.
+
+*/
+
+#define G_MOD 0x0000014d
+
+u4byte mds_rem(u4byte p0, u4byte p1)
+{ u4byte i, t, u;
+
+ for(i = 0; i < 8; ++i)
+ {
+ t = p1 >> 24; // get most significant coefficient
+
+ p1 = (p1 << 8) | (p0 >> 24); p0 <<= 8; // shift others up
+
+ // multiply t by a (the primitive element - i.e. left shift)
+
+ u = (t << 1);
+
+ if(t & 0x80) // subtract modular polynomial on overflow
+
+ u ^= G_MOD;
+
+ p1 ^= t ^ (u << 16); // remove t * (a * x^2 + 1)
+
+ u ^= (t >> 1); // form u = a * t + t / a = t * (a + 1 / a);
+
+ if(t & 0x01) // add the modular polynomial on underflow
+
+ u ^= G_MOD >> 1;
+
+ p1 ^= (u << 24) | (u << 8); // remove t * (a + 1/a) * (x^3 + x)
+ }
+
+ return p1;
+};
+
+/* initialise the key schedule from the user supplied key */
+
+u4byte *twofish_set_key(TwofishContext *ctx,
+ const u4byte in_key[], const u4byte key_len)
+{
+ u4byte i, a, b, me_key[4], mo_key[4];
+ u4byte *l_key = ctx->l_key;
+ u4byte *s_key = ctx->s_key;
+
+#ifdef Q_TABLES
+ if(!qt_gen)
+ {
+ gen_qtab(); qt_gen = 1;
+ }
+#endif
+
+#ifdef M_TABLE
+ if(!mt_gen)
+ {
+ gen_mtab(); mt_gen = 1;
+ }
+#endif
+
+ ctx->k_len = ctx->k_len = key_len / 64; /* 2, 3 or 4 */
+
+ for(i = 0; i < ctx->k_len; ++i)
+ {
+ a = in_key[i + i]; me_key[i] = a;
+ b = in_key[i + i + 1]; mo_key[i] = b;
+ s_key[ctx->k_len - i - 1] = mds_rem(a, b);
+ }
+
+ for(i = 0; i < 40; i += 2)
+ {
+ a = 0x01010101 * i; b = a + 0x01010101;
+ a = h_fun(ctx,a, me_key);
+ b = rotl(h_fun(ctx,b, mo_key), 8);
+ l_key[i] = a + b;
+ l_key[i + 1] = rotl(a + 2 * b, 9);
+ }
+
+#ifdef MK_TABLE
+ gen_mk_tab(ctx,s_key);
+#endif
+
+ return l_key;
+};
+
+/* encrypt a block of text */
+
+#define f_rnd(i) \
+ t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]); \
+ blk[2] = rotr(blk[2] ^ (t0 + t1 + l_key[4 * (i) + 8]), 1); \
+ blk[3] = rotl(blk[3], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 9]); \
+ t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]); \
+ blk[0] = rotr(blk[0] ^ (t0 + t1 + l_key[4 * (i) + 10]), 1); \
+ blk[1] = rotl(blk[1], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 11])
+
+void twofish_encrypt(TwofishContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[])
+{
+ u4byte t0, t1, blk[4];
+ u4byte *l_key = ctx->l_key;
+ u4byte *s_key = ctx->s_key;
+
+ blk[0] = in_blk[0] ^ l_key[0];
+ blk[1] = in_blk[1] ^ l_key[1];
+ blk[2] = in_blk[2] ^ l_key[2];
+ blk[3] = in_blk[3] ^ l_key[3];
+
+ f_rnd(0); f_rnd(1); f_rnd(2); f_rnd(3);
+ f_rnd(4); f_rnd(5); f_rnd(6); f_rnd(7);
+
+ out_blk[0] = blk[2] ^ l_key[4];
+ out_blk[1] = blk[3] ^ l_key[5];
+ out_blk[2] = blk[0] ^ l_key[6];
+ out_blk[3] = blk[1] ^ l_key[7];
+};
+
+/* decrypt a block of text */
+
+#define i_rnd(i) \
+ t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]); \
+ blk[2] = rotl(blk[2], 1) ^ (t0 + t1 + l_key[4 * (i) + 10]); \
+ blk[3] = rotr(blk[3] ^ (t0 + 2 * t1 + l_key[4 * (i) + 11]), 1); \
+ t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]); \
+ blk[0] = rotl(blk[0], 1) ^ (t0 + t1 + l_key[4 * (i) + 8]); \
+ blk[1] = rotr(blk[1] ^ (t0 + 2 * t1 + l_key[4 * (i) + 9]), 1)
+
+void twofish_decrypt(TwofishContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte t0, t1, blk[4];
+ u4byte *l_key = ctx->l_key;
+ u4byte *s_key = ctx->s_key;
+
+ blk[0] = in_blk[0] ^ l_key[4];
+ blk[1] = in_blk[1] ^ l_key[5];
+ blk[2] = in_blk[2] ^ l_key[6];
+ blk[3] = in_blk[3] ^ l_key[7];
+
+ i_rnd(7); i_rnd(6); i_rnd(5); i_rnd(4);
+ i_rnd(3); i_rnd(2); i_rnd(1); i_rnd(0);
+
+ out_blk[0] = blk[2] ^ l_key[0];
+ out_blk[1] = blk[3] ^ l_key[1];
+ out_blk[2] = blk[0] ^ l_key[2];
+ out_blk[3] = blk[1] ^ l_key[3];
+};
--- /dev/null
+/*
+
+ twofish.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:55 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef TWOFISH_H
+#define TWOFISH_H
+
+#include "twofish_internal.h"
+
+/*
+ * SILC Crypto API for Twofish
+ */
+
+SILC_CIPHER_API_SET_KEY(twofish);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(twofish);
+SILC_CIPHER_API_CONTEXT_LEN(twofish);
+SILC_CIPHER_API_ENCRYPT_CBC(twofish);
+SILC_CIPHER_API_DECRYPT_CBC(twofish);
+
+#endif
--- /dev/null
+/*
+
+ twofish_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef TWOFISH_INTERNAL_H
+#define TWOFISH_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+ u4byte k_len;
+ u4byte l_key[40];
+ u4byte s_key[4];
+} TwofishContext;
+
+/* Prototypes */
+u4byte *twofish_set_key(TwofishContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void twofish_encrypt(TwofishContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[]);
+void twofish_decrypt(TwofishContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+SUBDIRS = gmp-3.0.1
+
+noinst_LIBRARIES = libsilcmath.a
+
+libsilcmath_a_SOURCES = \
+ silcprimegen.c \
+ modinv.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcske \
+ -I../silcsim -I../.. -I../../includes \
+ -I./gmp-3.0.1
--- /dev/null
+/*
+
+ modinv.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+/* Table for finding multiplicative inverse */
+typedef struct {
+ SilcInt x;
+} ModInv;
+
+#define plus1 (i == 2 ? 0 : i + 1)
+#define minus1 (i == 0 ? 2 : i - 1)
+
+/* Find multiplicative inverse using Euclid's extended algorithm.
+ Computes inverse such that a * inv mod n = 1, where 0 < a < n.
+ Algorithm goes like this:
+
+ g(0) = n v(0) = 0
+ g(1) = a v(1) = 1
+
+ y = g(i-1) / g(i)
+ g(i+1) = g(i-1) - y * g(i) = g(i)-1 mod g(i)
+ v(i+1) = v(i-1) - y * v(i)
+
+ do until g(i) = 0, then inverse = v(i-1). If inverse is negative then n,
+ is added to inverse making it positive again. (Sometimes the algorithm
+ has a variable u defined too and it behaves just like v, except that
+ initalize values are swapped (i.e. u(0) = 1, u(1) = 0). However, u is
+ not needed by the algorithm so it does not have to be included.)
+*/
+
+void silc_mp_modinv(SilcInt *inv, SilcInt *a, SilcInt *n)
+{
+ int i;
+ SilcInt y;
+ SilcInt x;
+
+ ModInv g[3];
+ ModInv v[3];
+
+ /* init MP vars */
+ silc_mp_init(&y);
+ silc_mp_init(&x);
+ silc_mp_init_set_ui(&v[0].x, 0L); /* v(0) = 0 */
+ silc_mp_init_set_ui(&v[1].x, 1L); /* v(1) = 1 */
+ silc_mp_init(&v[2].x);
+ silc_mp_init_set(&g[0].x, n); /* g(0) = n */
+ silc_mp_init_set(&g[1].x, a); /* g(1) = a */
+ silc_mp_init(&g[2].x);
+
+ i = 1;
+ while(silc_mp_cmp_ui(&g[i].x, 0) != 0) {
+ silc_mp_div(&y, &g[minus1].x, &g[i].x); /* y = n / a */
+ silc_mp_mod(&g[plus1].x, &g[minus1].x, &g[i].x); /* remainder */
+ silc_mp_mul(&x, &y, &v[i].x);
+ silc_mp_set(&v[plus1].x, &v[minus1].x);
+ silc_mp_sub(&v[plus1].x, &v[plus1].x, &x);
+ i = plus1;
+ }
+
+ /* set the inverse */
+ silc_mp_set(inv, &v[minus1].x);
+
+ /* if inverse is negative, add n to inverse */
+ if (silc_mp_cmp_ui(inv, 0) < 0)
+ silc_mp_add(inv, inv, n);
+
+ /* clear the vars */
+ memset(&g, 0, sizeof(g));
+ memset(&v, 0, sizeof(v));
+ silc_mp_clear(&y);
+ silc_mp_clear(&x);
+ silc_mp_clear(&g[0].x);
+ silc_mp_clear(&g[1].x);
+ silc_mp_clear(&g[2].x);
+ silc_mp_clear(&v[0].x);
+ silc_mp_clear(&v[1].x);
+ silc_mp_clear(&v[2].x);
+}
--- /dev/null
+/*
+
+ modinv.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef MODINV_H
+#define MODINV_H
+
+void silc_mp_modinv(SilcInt *inv, SilcInt *a, SilcInt *n);
+
+#endif
--- /dev/null
+/*
+
+ silcmp.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCMP_H
+#define SILCMP_H
+
+#include "gmp.h"
+
+/* SILC MP library definitions. We use GNU MP library as default
+ MP library. However, to make possible future changes easier (SILC
+ might have its own MP library in the future) we implement our own
+ MP API with simple macros. */
+
+typedef MP_INT SilcInt;
+#define silc_mp_abs(a, b) mpz_abs((a), (b))
+#define silc_mp_add(a, b, c) mpz_add((a), (b), (c))
+#define silc_mp_add_ui(a, b, c) mpz_add_ui((a), (b), (c))
+#define silc_mp_and(a, b, c) mpz_and((a), (b), (c))
+#define silc_mp_cdiv_q(a, b, c) mpz_cdiv_q((a), (b), (c))
+#define silc_mp_cdiv_q_ui(a, b, c) mpz_cdiv_q_ui((a), (b), (c))
+#define silc_mp_cdiv_r(a, b, c) mpz_cdiv_r((a), (b), (c))
+#define silc_mp_cdiv_r_ui(a, b, c) mpz_cdiv_r_ui((a), (b), (c))
+#define silc_mp_cdiv_ui(a, b) mpz_cdiv_ui((a), (b))
+#define silc_mp_clear(a) mpz_clear((a))
+#define silc_mp_clrbit(a, b) mpz_clrbit((a), (b))
+#define silc_mp_cmp(a, b) mpz_cmp((a), (b))
+#define silc_mp_cmp_si(a, b) mpz_cmp_si((a), (b))
+#define silc_mp_cmp_ui(a, b) mpz_cmp_ui((a), (b))
+#define silc_mp_com(a, b) mpz_com((a), (b))
+#define silc_mp_divexact(a, b, c) mpz_divexact((a), (b), (c))
+#define silc_mp_div(a, b, c) mpz_div((a), (b), (c))
+#define silc_mp_div_ui(a, b, c) mpz_div_ui((a), (b), (c))
+#define silc_mp_fdiv_ui(a, b) mpz_fdiv_ui((a), (b))
+#define silc_mp_fdiv_q(a, b, c) mpz_fdiv_q((a), (b), (c))
+#define silc_mp_fdiv_q_2exp(a, b, c) mpz_fdiv_q_2exp((a), (b), (c))
+#define silc_mp_fdiv_q_ui(a, b, c) mpz_fdiv_q_ui((a), (b), (c))
+#define silc_mp_fdiv_qr(a, b, c, d) mpz_fdiv_qr((a), (b), (c), (d))
+#define silc_mp_fdiv_qr_ui(a, b, c, d) mpz_fdiv_qr_ui((a), (b), (c), (d))
+#define silc_mp_fdiv_r(a, b, c) mpz_fdiv_r((a), (b), (c))
+#define silc_mp_fdiv_r_2exp(a, b, c) mpz_fdiv_r_2exp((a), (b), (c))
+#define silc_mp_fdiv_r_ui(a, b, c) mpz_fdiv_r_ui((a), (b), (c))
+#define silc_mp_fdiv_ui(a, b) mpz_fdiv_ui((a), (b))
+#define silc_mp_gcd(a, b, c) mpz_gcd((a), (b), (c))
+#define silc_mp_gcd_ui(a, b, c) mpz_gcd_ui((a), (b), (c))
+#define silc_mp_gcdext(a, b, c, d, e) mpz_gcdext((a), (b), (c), (d), (e))
+#define silc_mp_get_ui(a) mpz_get_ui((a))
+#define silc_mp_init(a) mpz_init((a))
+#define silc_mp_init_set(a, b) mpz_init_set((a), (b))
+#define silc_mp_init_set_d(a, b) mpz_init_set_d((a), (b))
+#define silc_mp_init_set_si(a, b) mpz_init_set_si((a), (b))
+#define silc_mp_init_set_str(a, b, c) mpz_init_set_str((a), (b), (c))
+#define silc_mp_init_set_ui(a, b) mpz_init_set_ui((a), (b))
+#define silc_mp_invert(a, b, c) mpz_invert((a), (b), (c))
+#define silc_mp_ior(a, b, c) mpz_ior((a), (b), (c))
+#define silc_mp_mod(a, b, c) mpz_mod((a), (b), (c))
+#define silc_mp_mod_2exp(a, b, c) mpz_mod_2exp((a), (b), (c))
+#define silc_mp_mod_ui(a, b, c) mpz_mod_ui((a), (b), (c))
+#define silc_mp_mul(a, b, c) mpz_mul((a), (b), (c))
+#define silc_mp_mul_2exp(a, b, c) mpz_mul_2exp((a), (b), (c))
+#define silc_mp_mul_ui(a, b, c) mpz_mul_ui((a), (b), (c))
+#define silc_mp_neg(a, b) mpz_neg((a), (b))
+#define silc_mp_pow_ui(a, b, c) mpz_pow_ui((a), (b), (c))
+#define silc_mp_powm(a, b, c, d) mpz_powm((a), (b), (c), (d))
+#define silc_mp_powm_ui(a, b, c, d) mpz_powm_ui((a), (b), (c), (d))
+#define silc_mp_probab_prime_p(a, b) mpz_probab_prime_p((a), (b))
+#define silc_mp_set(a, b) mpz_set((a), (b))
+#define silc_mp_set_d(a, b) mpz_set_d((a), (b))
+#define silc_mp_set_f(a, b) mpz_set_f((a), (b))
+#define silc_mp_set_q(a, b) mpz_set_q((a), (b))
+#define silc_mp_set_si(a, b) mpz_set_si((a), (b))
+#define silc_mp_set_str(a, b, c) mpz_set_str((a), (b), (c))
+#define silc_mp_set_ui(a, b) mpz_set_ui((a), (b))
+#define silc_mp_setbit(a, b) mpz_setbit((a), (b))
+#define silc_mp_size(a) mpz_size((a))
+#define silc_mp_sizeinbase(a, b) mpz_sizeinbase((a), (b))
+#define silc_mp_sqrt(a, b) mpz_sqrt((a), (b))
+#define silc_mp_sqrtrem(a, b, c) mpz_sqrtrem((a), (b), (c))
+#define silc_mp_sub(a, b, c) mpz_sub((a), (b), (c))
+#define silc_mp_sub_ui(a, b, c) mpz_sub_ui((a), (b), (c))
+#define silc_mp_tdiv_ui(a, b) mpz_tdiv_ui((a), (b))
+#define silc_mp_tdiv_q(a, b, c) mpz_tdiv_q((a), (b), (c))
+#define silc_mp_tdiv_q_2exp(a, b, c) mpz_tdiv_q_2exp((a), (b), (c))
+#define silc_mp_tdiv_q_ui(a, b, c) mpz_tdiv_q_ui((a), (b), (c))
+#define silc_mp_tdiv_qr(a, b, c, d) mpz_tdiv_qr((a), (b), (c), (d))
+#define silc_mp_tdiv_qr_ui(a, b, c, d) mpz_tdiv_qr_ui((a), (b), (c), (d))
+#define silc_mp_tdiv_r(a, b, c) mpz_tdiv_r((a), (b), (c))
+#define silc_mp_tdiv_r_2exp(a, b, c) mpz_tdiv_r_2exp((a), (b), (c))
+#define silc_mp_tdiv_r_ui(a, b, c) mpz_tdiv_r_ui((a), (b), (c))
+#define silc_mp_tdiv_ui(a, b) mpz_tdiv_ui((a), (b))
+#define silc_mp_ui_pow_ui(a, b, c) mpz_ui_pow_ui((a), (b), (c))
+#define silc_mp_get_str(a, b, c) mpz_get_str((a), (b), (c))
+#define silc_mp_out_str(a, b, c) mpz_out_str((a), (b), (c))
+
+#endif
--- /dev/null
+/*
+
+ silcprimegen.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Created: Mon Dec 8 16:35:37 GMT+0200 1997
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:51 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* XXX This must be temporary solution!! yucky! */
+/* Global random pool used for all prime generation. All primes generated
+ in SILC uses this same pool. Before primes can be generated one must
+ call silc_math_primegen_init. */
+static SilcRng primegen_rng;
+
+/*
+ Fixed primetable for small prime division. We use this primetable to
+ test if possible prime is divisible any of these. Primetable is NULL
+ terminated. This same primetable can be found in SSH and PGP except that
+ SSH don't have prime 2 in the table. This sort of prime table is easily
+ created, for example, using sieve of Erastosthenes.
+
+ Just to include; if somebody is interested about Erastosthenes. Creating a
+ small prime table using sieve of Erastosthenes would go like this: Write
+ down a list of integers in range of 2 to n. Here in example n = 20.
+
+ 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+
+ Then mark all multiples of 2 (Note: 2 is a prime number):
+
+ 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ x x x x x x x x x
+
+ Move to the next unmarked number, 3, then mark all multiples of 3.
+
+ 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ x x x x x x x x x x x
+
+ And continue doing this, marking all multiples of the next unmarked
+ number until there are now new unmarked numbers. And there you have a
+ prime table. So in this example, primes between 2 - 20 are:
+
+ 2 3 5 7 11 13 17 19
+
+*/
+
+static unsigned int primetable[] =
+{
+ 2, 3, 5, 7, 11, 13, 17, 19,
+ 23, 29, 31, 37, 41, 43, 47, 53,
+ 59, 61, 67, 71, 73, 79, 83, 89,
+ 97, 101, 103, 107, 109, 113, 127, 131,
+ 137, 139, 149, 151, 157, 163, 167, 173,
+ 179, 181, 191, 193, 197, 199, 211, 223,
+ 227, 229, 233, 239, 241, 251, 257, 263,
+ 269, 271, 277, 281, 283, 293, 307, 311,
+ 313, 317, 331, 337, 347, 349, 353, 359,
+ 367, 373, 379, 383, 389, 397, 401, 409,
+ 419, 421, 431, 433, 439, 443, 449, 457,
+ 461, 463, 467, 479, 487, 491, 499, 503,
+ 509, 521, 523, 541, 547, 557, 563, 569,
+ 571, 577, 587, 593, 599, 601, 607, 613,
+ 617, 619, 631, 641, 643, 647, 653, 659,
+ 661, 673, 677, 683, 691, 701, 709, 719,
+ 727, 733, 739, 743, 751, 757, 761, 769,
+ 773, 787, 797, 809, 811, 821, 823, 827,
+ 829, 839, 853, 857, 859, 863, 877, 881,
+ 883, 887, 907, 911, 919, 929, 937, 941,
+ 947, 953, 967, 971, 977, 983, 991, 997,
+ 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049,
+ 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
+ 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
+ 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
+ 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283,
+ 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321,
+ 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423,
+ 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459,
+ 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
+ 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571,
+ 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619,
+ 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693,
+ 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747,
+ 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
+ 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
+ 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949,
+ 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003,
+ 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069,
+ 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129,
+ 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203,
+ 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267,
+ 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311,
+ 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377,
+ 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423,
+ 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503,
+ 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579,
+ 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657,
+ 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693,
+ 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
+ 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801,
+ 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861,
+ 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939,
+ 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011,
+ 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079,
+ 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167,
+ 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221,
+ 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301,
+ 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347,
+ 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413,
+ 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491,
+ 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541,
+ 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
+ 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671,
+ 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727,
+ 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797,
+ 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863,
+ 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923,
+ 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003,
+ 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057,
+ 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129,
+ 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211,
+ 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259,
+ 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337,
+ 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
+ 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481,
+ 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547,
+ 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621,
+ 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673,
+ 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751,
+ 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813,
+ 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909,
+ 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967,
+ 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011,
+ 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087,
+ 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167,
+ 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233,
+ 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309,
+ 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399,
+ 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443,
+ 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507,
+ 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573,
+ 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653,
+ 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711,
+ 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791,
+ 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849,
+ 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897,
+ 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007,
+ 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073,
+ 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133,
+ 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211,
+ 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271,
+ 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329,
+ 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379,
+ 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473,
+ 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563,
+ 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637,
+ 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701,
+ 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779,
+ 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833,
+ 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907,
+ 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971,
+ 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027,
+ 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121,
+ 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207,
+ 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253,
+ 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349,
+ 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457,
+ 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517,
+ 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561,
+ 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621,
+ 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691,
+ 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757,
+ 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853,
+ 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919,
+ 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009,
+ 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087,
+ 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161,
+ 8167, 8171, 8179, 8191, 0
+};
+
+
+/* Find appropriate prime. It generates a number by taking random bytes.
+ It then tests the number that it's not divisible by any of the small
+ primes and then it performs Fermat's prime test. I thank Rieks Joosten
+ (r.joosten@pijnenburg.nl) for such a good help with prime tests.
+
+ If argument verbose is TRUE this will display some status information
+ about the progress of generation. */
+
+int silc_math_gen_prime(SilcInt *prime, unsigned int bits, int verbose)
+{
+ unsigned char *numbuf;
+ unsigned int i, b, k;
+ unsigned int *spmods;
+ SilcInt r, base, tmp, tmp2, oprime;
+
+ /* XXX */
+ assert(primegen_rng != NULL);
+
+ silc_mp_init(&r);
+ silc_mp_init_set_ui(&base, 2);
+ silc_mp_init(&tmp);
+ silc_mp_init(&tmp2);
+ silc_mp_init(&oprime);
+
+ SILC_LOG_DEBUG(("Generating new prime"));
+
+ /* Get random number */
+ numbuf = silc_rng_get_rn_string(primegen_rng, (bits / 8));
+ if (!numbuf)
+ return FALSE;
+
+ /* Convert into MP and set the size */
+ silc_mp_set_str(prime, numbuf, 16);
+ silc_mp_mod_2exp(prime, prime, bits);
+
+ /* Empty buffer */
+ memset(numbuf, 0, (bits / 8));
+ silc_free(numbuf);
+
+ /* Number could be even number, so we'll make it odd. */
+ silc_mp_set_ui(&tmp, 1);
+ silc_mp_ior(prime, prime, &tmp); /* OR operator */
+
+ /* Init modulo table with the prime candidate and the primes
+ in the primetable. */
+ spmods = silc_malloc(sizeof(primetable) * sizeof(unsigned int));
+ for (i = 0; primetable[i] != 0; i++) {
+ silc_mp_mod_ui(&tmp, prime, primetable[i]);
+ spmods[i] = silc_mp_get_ui(&tmp);
+ }
+
+ /* k is added by 2, this way we skip all even numbers (prime is odd). */
+ silc_mp_set(&oprime, prime);
+ for (k = 0;; k += 2) {
+ silc_mp_add_ui(&oprime, prime, k);
+
+ /* See if the prime has a divisor in primetable[].
+ * If it has then it's a composite. We add k to the
+ * original modulo value, k is added by 2 on every roll.
+ * This way we don't have to re-init the whole table if
+ * the number is composite.
+ */
+ for (b = 0; b < i; b++) {
+ silc_mp_set_ui(&tmp2, spmods[b]);
+ silc_mp_add_ui(&tmp2, &tmp2, k);
+ silc_mp_mod_ui(&tmp, &tmp2, primetable[b]);
+
+ /* If mod is 0, the number is composite */
+ if (silc_mp_cmp_ui(&tmp, 0) == 0)
+ break;
+ }
+ if (b < i)
+ continue;
+
+ /* Passed the quick test. */
+
+ /* Does the prime pass the Fermat's prime test.
+ * r = 2 ^ p mod p, if r == 2, then p is probably a prime.
+ */
+ silc_mp_powm(&r, &base, &oprime, &oprime);
+ if (silc_mp_cmp_ui(&r, 2) != 0) {
+ if (verbose) {
+ printf(".");
+ fflush(stdout);
+ }
+ continue;
+ }
+
+ /* Passed the Fermat's test. And I don't think
+ * we have to do more tests. If anyone wants to do more
+ * tests, MP library has probability of prime test:
+ *
+ * if (silc_mp_probab_prime_p(prime, 25))
+ * break; found a probable prime
+ *
+ * However, this is very slow.
+ */
+ /* XXX: this could be done if some argument, say strict_primes, is
+ TRUE when we are willing to spend more time on the prime test and
+ to get, perhaps, better primes. */
+ silc_mp_set(prime, &oprime);
+ break;
+ }
+
+ silc_free(spmods);
+ silc_mp_clear(&r);
+ silc_mp_clear(&base);
+ silc_mp_clear(&tmp);
+ silc_mp_clear(&tmp2);
+ silc_mp_clear(&oprime);
+
+ return TRUE;
+}
+
+/* Performs primality testings for given number. Returns TRUE if the
+ number is probably a prime. */
+
+int silc_math_prime_test(SilcInt *p)
+{
+ SilcInt r, base, tmp;
+ int i, ret = 0;
+
+ silc_mp_init(&r);
+ silc_mp_init(&tmp);
+ silc_mp_init_set_ui(&base, 2);
+
+ SILC_LOG_DEBUG(("Testing probability of prime"));
+
+ /* See if the number is divisible by any of the
+ small primes in primetable[]. */
+ for (i = 0; primetable[i] != 0; i++) {
+ silc_mp_mod_ui(&tmp, p, primetable[i]);
+
+ /* If mod is 0, the number is composite */
+ if (silc_mp_cmp_ui(&tmp, 0) == 0)
+ ret = -1;
+ }
+
+ /* Does the prime pass the Fermat's prime test.
+ * r = 2 ^ p mod p, if r == 2, then p is probably a prime.
+ */
+ silc_mp_powm(&r, &base, p, p);
+ if (silc_mp_cmp_ui(&r, 2) != 0)
+ ret = -1;
+
+ silc_mp_clear(&r);
+ silc_mp_clear(&tmp);
+ silc_mp_clear(&base);
+
+ if (ret)
+ return FALSE;
+
+ /* Number is probably a prime */
+ return TRUE;
+}
+
+/* XXX This must temporary solution!! */
+/* Initializes the random pool used to generated primes */
+
+void silc_math_primegen_init()
+{
+ SILC_LOG_DEBUG(("Start"));
+
+ if (primegen_rng == NULL) {
+ primegen_rng = silc_rng_alloc();
+ silc_rng_init(primegen_rng);
+ }
+}
+
+/* XXX This must temporary solution!! */
+/* Uninitializes random pool */
+
+void silc_math_primegen_uninit()
+{
+ silc_rng_free(primegen_rng);
+}
--- /dev/null
+/*
+
+ silcprimegen.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPRIMEGEN_H
+#define SILCPRIMEGEN_H
+
+int silc_math_gen_prime(SilcInt *prime, unsigned int bits, int verbose);
+int silc_math_prime_test(SilcInt *p);
+void silc_math_primegen_init();
+void silc_math_primegen_uninit();
+
+#endif
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilcsim.a
+
+libsilcsim_a_SOURCES = \
+ silcsim.c \
+ silcsimutil.c
+
+SIM_CFLAGS = -fPIC -shared
+
+SIM_MODULES_DIR = modules
+
+SUBDIRS = modules
+
+#
+# SILC Ciphers to be compiled as modules
+#
+SIM_CIPHER_OBJS = \
+ none.o \
+ blowfish.o \
+ rc5.o \
+ rc6.o \
+ mars.o \
+ rijndael.o \
+ rsa.o \
+ twofish.o
+
+#
+# SILC Hash Functions to be compiled as modules
+#
+SIM_HASH_OBJS = \
+ md5.o \
+ sha1.o
+
+all: $(SIM_CIPHER_OBJS) $(SIM_HASH_OBJS)
+
+$(SIM_CIPHER_OBJS): ../silccrypt/libsilccrypt.a
+ rm -rf $*.c $*.o
+ $(LN_S) $(srcdir)/../silccrypt/$*.c
+ $(COMPILE) $(SIM_CFLAGS) $*.c -o $(SIM_MODULES_DIR)/$*.sim.so
+ $(LN_S) $(srcdir)/$(SIM_MODULES_DIR)/$*.sim.so $*.o
+ rm -rf $*.c
+
+$(SIM_HASH_OBJS): ../silccrypt/libsilccrypt.a
+ rm -rf $*.c $*.o
+ $(LN_S) $(srcdir)/../silccrypt/$*.c
+ $(COMPILE) $(SIM_CFLAGS) $*.c -o $(SIM_MODULES_DIR)/$*.sim.so
+ $(LN_S) $(srcdir)/$(SIM_MODULES_DIR)/$*.sim.so $*.o
+ rm -rf $*.c
+
+CLEANFILES = $(SIM_MODULES_DIR)/*.sim.so
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
+ -I../silccore -I../.. -I../../includes \
+ -I../silcmath/gmp-3.0.1
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+all:
+ -cd ..
--- /dev/null
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../../includes/silcdefs.h
+CONFIG_CLEAN_FILES =
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/silcsim/modules/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib/silcsim/modules
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file; \
+ done
+info:
+dvi:
+check: all
+ $(MAKE)
+installcheck:
+install-exec:
+ @$(NORMAL_INSTALL)
+
+install-data:
+ @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+ @:
+
+uninstall:
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(DISTCLEANFILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-generic
+
+clean: clean-generic mostlyclean
+
+distclean: distclean-generic clean
+ -rm -f config.status
+
+maintainer-clean: maintainer-clean-generic distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+all:
+ -cd ..
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+
+ silcsim.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ These routines implement the SILC Module (SIM) support. SIM's are
+ dynamically run-time loaded shared objects that can implement some
+ routines SILC can use to extend its features. Currently all
+ SILC Crypto modules are implemented as SIM's. They all implement
+ the SILC Crypto API and can be loaded run-time into the SILC and
+ used when needed.
+
+ Basically any SILC API can be implemented as SIM, however, currently
+ only SILC Crypto modules (ciphers and hash functions (PKCS are not
+ supported)) are supported.
+
+ This implementation expects that no SILC specific symbols needs to
+ be exported into the SIM's. This means that SIM's cannot directly
+ use SILC specific symbols or definitions. This feature can be
+ supported with SIM's but currently (with Crypto modules) this is
+ not needed.
+
+ NOTE: These routines maybe highly system dependant thus I can expect
+ some heavy #ifdef's here. However, I'm more happy to see some macro
+ SIM API and restrict the #ifdef's to silcsim.h file.
+
+*/
+
+#include "silcincludes.h"
+
+#ifdef SILC_SIM /* SIM upport enabled */
+
+/* Allocates new SIM context. This is later send to all SIM
+ routines. */
+
+SilcSimContext *silc_sim_alloc()
+{
+ SilcSimContext *new;
+
+ SILC_LOG_DEBUG(("Initializing new SIM context"));
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new) {
+ SILC_LOG_ERROR(("Could not allocate new SIM context"));
+ return NULL;
+ }
+
+ new->handle = NULL;
+ new->type = SILC_SIM_NONE;
+ new->libname = NULL;
+ new->flags = SILC_SIM_FLAGS;
+
+ return new;
+}
+
+/* Free's SIM context. SIM must be closed with silc_sim_close before
+ calling this. */
+
+void silc_sim_free(SilcSimContext *sim)
+{
+ assert(sim->handle == NULL);
+
+ if (sim)
+ silc_free(sim);
+}
+
+/* Loads SIM into the SILC system. */
+
+int silc_sim_load(SilcSimContext *sim)
+{
+ assert(sim != NULL);
+
+ SILC_LOG_DEBUG(("Loading SIM '%s'", sim->libname));
+
+ /* Load the library */
+ sim->handle = dlopen(sim->libname, sim->flags);
+ if (!sim->handle) {
+ SILC_LOG_ERROR(("Error loading SIM: %s", silc_sim_error()));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Closes SIM. This is called when execution of program is ending or
+ one explicitly wants to remove this SIM from SILC. */
+
+int silc_sim_close(SilcSimContext *sim)
+{
+ assert(sim != NULL);
+
+ SILC_LOG_DEBUG(("Closing SIM '%s'", sim->libname));
+
+ /* Close the library */
+ dlclose(sim->handle);
+
+ return TRUE;
+}
+
+/* Returns error string if error has occured while processing SIM's. */
+
+char *silc_sim_error()
+{
+ return dlerror();
+}
+
+/* Returns opaque pointer for a symbol in SIM. Caller must know the
+ symbols they want to get from SIM and use the returned pointer to
+ what ever it is intended. */
+
+void *silc_sim_getsym(SilcSimContext *sim, const char *symbol)
+{
+ assert(sim != NULL);
+
+ SILC_LOG_DEBUG(("Getting symbol '%s' from SIM", symbol));
+
+ return dlsym(sim->handle, symbol);
+}
+
+#endif /* SILC_SIM */
--- /dev/null
+/*
+
+ silcsim.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSIM_H
+#define SILCSIM_H
+
+/* All SIM types. New types maybe freely added. */
+typedef enum {
+ SILC_SIM_NONE = 0,
+ SILC_SIM_CIPHER,
+ SILC_SIM_HASH,
+} SilcSimType;
+
+/*
+ SILC Module (SIM) Context.
+
+ This context holds relevant information about the SIM loaded into
+ the system. Following short description of the fields.
+
+ void *handle
+
+ Pointer to the SIM. This is used to get the symbols out of
+ the SIM. This is initalized by system specific routine.
+
+ SilcSimType type
+
+ Type of the SIM.
+
+ char *libname;
+
+ Filename and path to the SIM library file.
+
+ int flags
+
+ Flags used with the SIM. These are system specific flags.
+ See below for more information.
+
+*/
+typedef struct {
+ void *handle;
+ SilcSimType type;
+ char *libname;
+ int flags;
+} SilcSimContext;
+
+/* Flags used to retrieve the symbols from the library file. Default
+ is that the symbols are resolved as they are loaded. However, if
+ system doesn't support this we have no other choice but to do it lazy
+ thus experience some overhead when using the symbol first time. */
+#define SILC_SIM_FLAGS RTLD_NOW
+/*#define SILC_SIM_FLAGS RTLD_LAZY */
+
+/* Prototypes */
+SilcSimContext *silc_sim_alloc();
+void silc_sim_free(SilcSimContext *sim);
+int silc_sim_load(SilcSimContext *sim);
+int silc_sim_close(SilcSimContext *sim);
+char *silc_sim_error();
+void *silc_sim_getsym(SilcSimContext *sim, const char *symbol);
+
+#endif
--- /dev/null
+/*
+
+ silcsimutil.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+#ifdef SILC_SIM /* SIM support enabled */
+
+/* This puts two arguments together and returns a new allocated string.
+ This is used to produce the function names that are then get from
+ SIM's. */
+
+char *silc_sim_symname(char *symbol, char *function)
+{
+ char *ret;
+ int len1, len2, len3;
+
+ len1 = strlen(symbol);
+ len2 = strlen(function);
+ len3 = strlen(SILC_SIM_SYMBOL_PREFIX);
+ ret = silc_calloc(len1 + len2 + len3 + 2 + 1, sizeof(char));
+
+ strncpy(ret, SILC_SIM_SYMBOL_PREFIX, len3);
+ strncat(ret, "_", 1);
+ strncat(ret, symbol, len1);
+ strncat(ret, "_", 1);
+ strncat(ret, function, len2);
+
+ return ret;
+}
+
+#endif /* SILC_SIM */
--- /dev/null
+/*
+
+ silcsimutil.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSIMUTIL_H
+#define SILCSIMUTIL_H
+
+#define SILC_SIM_SYMBOL_PREFIX "silc"
+
+/* Prototypes */
+
+char *silc_sim_symname(char *symbol, char *function);
+
+#endif
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilcske.a
+
+libsilcske_a_SOURCES = \
+ silcske.c \
+ payload.c \
+ groups.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silccore \
+ -I../silcsim -I../silcmath -I../.. -I../../includes \
+ -I../silcmath/gmp-3.0.1
--- /dev/null
+/*
+
+ groups.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "groups_internal.h"
+
+/* Fixed and public Diffie Hellman Groups defined by the SKE
+ protocol. These are equivalent to the OAKLEY Key Determination
+ protocol groups (taken from RFC 2412). */
+const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[] =
+{
+ /* 1024 bits modulus (Mandatory group) */
+ { 1, "diffie-hellman-group1",
+ "0x"
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381"
+ "FFFFFFFF FFFFFFFF",
+ "0x"
+ "7FFFFFFF FFFFFFFF E487ED51 10B4611A 62633145 C06E0E68"
+ "94812704 4533E63A 0105DF53 1D89CD91 28A5043C C71A026E"
+ "F7CA8CD9 E69D218D 98158536 F92F8A1B A7F09AB6 B6A8E122"
+ "F242DABB 312F3F63 7A262174 D31BF6B5 85FFAE5B 7A035BF6"
+ "F71C35FD AD44CFD2 D74F9208 BE258FF3 24943328 F67329C0"
+ "FFFFFFFF FFFFFFFF",
+ "0x2" },
+
+ /* 1536 bits modulus (Optional group) */
+ { 2, "diffie-hellman-group2",
+ "0x"
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D"
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F"
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D"
+ "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF",
+ "0x"
+ "7FFFFFFF FFFFFFFF E487ED51 10B4611A 62633145 C06E0E68"
+ "94812704 4533E63A 0105DF53 1D89CD91 28A5043C C71A026E"
+ "F7CA8CD9 E69D218D 98158536 F92F8A1B A7F09AB6 B6A8E122"
+ "F242DABB 312F3F63 7A262174 D31BF6B5 85FFAE5B 7A035BF6"
+ "F71C35FD AD44CFD2 D74F9208 BE258FF3 24943328 F6722D9E"
+ "E1003E5C 50B1DF82 CC6D241B 0E2AE9CD 348B1FD4 7E9267AF"
+ "C1B2AE91 EE51D6CB 0E3179AB 1042A95D CF6A9483 B84B4B36"
+ "B3861AA7 255E4C02 78BA3604 6511B993 FFFFFFFF FFFFFFFF",
+ "0x2" },
+
+ { 0, NULL, NULL, NULL }
+};
+
+/* Returns Diffie Hellman group by group number */
+
+SilcSKEStatus silc_ske_get_group_by_number(int number,
+ SilcSKEDiffieHellmanGroup *ret)
+{
+ int i;
+ SilcSKEDiffieHellmanGroup group;
+
+ for (i = 0; silc_ske_groups[i].name; i++) {
+ if (silc_ske_groups[i].number == number)
+ break;
+ }
+
+ if (silc_ske_groups[i].name == NULL)
+ return SILC_SKE_STATUS_UNKNOWN_GROUP;
+
+ /* Return the group */
+ if (ret) {
+ group = silc_calloc(1, sizeof(*group));
+ group->number = number;
+ group->name = silc_ske_groups[i].name;
+ silc_mp_init(&group->group);
+ silc_mp_init(&group->group_order);
+ silc_mp_init(&group->generator);
+ silc_mp_set_str(&group->group, silc_ske_groups[i].group, 0);
+ silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 0);
+ silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 0);
+
+ *ret = group;
+ }
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Returns Diffie Hellman group by name */
+
+SilcSKEStatus silc_ske_get_group_by_name(const char *name,
+ SilcSKEDiffieHellmanGroup *ret)
+{
+ int i;
+ SilcSKEDiffieHellmanGroup group;
+
+ for (i = 0; silc_ske_groups[i].name; i++) {
+ if (!strcmp(silc_ske_groups[i].name, name))
+ break;
+ }
+
+ if (silc_ske_groups[i].name == NULL)
+ return SILC_SKE_STATUS_UNKNOWN_GROUP;
+
+ /* Return the group */
+ if (ret) {
+ group = silc_calloc(1, sizeof(*group));
+ group->number = silc_ske_groups[i].number;
+ group->name = silc_ske_groups[i].name;
+ silc_mp_init(&group->group);
+ silc_mp_init(&group->group_order);
+ silc_mp_init(&group->generator);
+ silc_mp_set_str(&group->group, silc_ske_groups[i].group, 0);
+ silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 0);
+ silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 0);
+
+ *ret = group;
+ }
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Returns comma separated list of supported groups */
+
+char *silc_ske_get_supported_groups()
+{
+ char *list = NULL;
+ int i, len;
+
+ len = 0;
+ for (i = 0; silc_ske_groups[i].name; i++) {
+ len += strlen(silc_ske_groups[i].name);
+ list = silc_realloc(list, len + 1);
+
+ memcpy(list + (len - strlen(silc_ske_groups[i].name)),
+ silc_ske_groups[i].name, strlen(silc_ske_groups[i].name));
+ memcpy(list + len, ",", 1);
+ len++;
+ }
+
+ list[len - 1] = 0;
+
+ return list;
+}
--- /dev/null
+/*
+
+ groups.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef GROUPS_H
+#define GROUPS_H
+
+#include "silcske_status.h"
+#include "groups_internal.h"
+
+/* Forward declaration */
+typedef struct SilcSKEDiffieHellmanGroupStruct *SilcSKEDiffieHellmanGroup;
+
+/* List of defined groups. */
+extern const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[];
+
+/* Prototypes */
+SilcSKEStatus silc_ske_get_group_by_number(int number,
+ SilcSKEDiffieHellmanGroup *ret);
+SilcSKEStatus silc_ske_get_group_by_name(const char *name,
+ SilcSKEDiffieHellmanGroup *ret);
+char *silc_ske_get_supported_groups();
+
+#endif
--- /dev/null
+/*
+
+ groups_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef GROUPS_INTERNAL_H
+#define GROUPS_INTERNAL_H
+
+/* Diffie Hellman Group. Defines the group name, prime, largest prime
+ factor (group order) and generator. */
+struct SilcSKEDiffieHellmanGroupDefStruct {
+ int number;
+ char *name;
+ char *group;
+ char *group_order;
+ char *generator;
+};
+
+struct SilcSKEDiffieHellmanGroupStruct {
+ int number;
+ char *name;
+ SilcInt group;
+ SilcInt group_order;
+ SilcInt generator;
+};
+
+#endif
--- /dev/null
+/*
+
+ payload.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/* XXX TODO: This is not optimized version and should be optimized!
+ Use *_ALLOC buffer formatting in payload decodings! */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "payload_internal.h"
+
+/* Temporary buffer used in payload decoding */
+unsigned char buf[16384];
+
+/* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
+ to the other end. */
+
+SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
+ SilcSKEStartPayload *payload,
+ SilcBuffer *return_buffer)
+{
+ SilcBuffer buf;
+
+ SILC_LOG_DEBUG(("Encoding KE Start Payload"));
+
+ if (!payload)
+ return SILC_SKE_STATUS_ERROR;
+
+ /* Allocate channel payload buffer. */
+ buf = silc_buffer_alloc(payload->len);
+ if (!buf) {
+ SILC_LOG_ERROR(("Could not allocate encode buffer"));
+ return SILC_SKE_STATUS_ERROR;
+ }
+
+ silc_buffer_pull_tail(buf, payload->len);
+
+ /* Encode the payload */
+ silc_buffer_format(buf,
+ SILC_STR_UI_CHAR(0), /* RESERVED field */
+ SILC_STR_UI_CHAR(payload->flags),
+ SILC_STR_UI_SHORT(payload->len),
+ SILC_STR_UI_XNSTRING(payload->cookie,
+ payload->cookie_len),
+ SILC_STR_UI_SHORT(payload->ke_grp_len),
+ SILC_STR_UI_XNSTRING(payload->ke_grp_list,
+ payload->ke_grp_len),
+ SILC_STR_UI_SHORT(payload->pkcs_alg_len),
+ SILC_STR_UI_XNSTRING(payload->pkcs_alg_list,
+ payload->pkcs_alg_len),
+ SILC_STR_UI_SHORT(payload->enc_alg_len),
+ SILC_STR_UI_XNSTRING(payload->enc_alg_list,
+ payload->enc_alg_len),
+ SILC_STR_UI_SHORT(payload->hash_alg_len),
+ SILC_STR_UI_XNSTRING(payload->hash_alg_list,
+ payload->hash_alg_len),
+ SILC_STR_UI_SHORT(payload->comp_alg_len),
+ SILC_STR_UI_XNSTRING(payload->comp_alg_list,
+ payload->comp_alg_len),
+ SILC_STR_END);
+
+ /* Return the encoded buffer */
+ *return_buffer = buf;
+
+ SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, buf->len);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Parses the Key Exchange Start Payload. Parsed data is returned
+ to allocated payload structure. */
+
+SilcSKEStatus
+silc_ske_payload_start_decode(SilcSKE ske,
+ SilcBuffer buffer,
+ SilcSKEStartPayload **return_payload)
+{
+ SilcSKEStartPayload *payload;
+ SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
+ unsigned char tmp;
+ int len, len2;
+
+ SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
+
+ SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, buffer->len);
+
+ payload = silc_calloc(1, sizeof(*payload));
+ memset(buf, 0, sizeof(buf));
+
+ /* Parse the entire payload */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_CHAR(&tmp), /* RESERVED Field */
+ SILC_STR_UI_CHAR(&payload->flags),
+ SILC_STR_UI_SHORT(&payload->len),
+ SILC_STR_UI_XNSTRING(&buf, SILC_SKE_COOKIE_LEN),
+ SILC_STR_UI_SHORT(&payload->ke_grp_len),
+ SILC_STR_END);
+
+ if (tmp != 0) {
+ SILC_LOG_DEBUG(("Bad reserved field"));
+ status = SILC_SKE_STATUS_BAD_RESERVED_FIELD;
+ goto err;
+ }
+
+ if (payload->len != buffer->len) {
+ SILC_LOG_DEBUG(("Bad payload length"));
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ if (payload->ke_grp_len < 1) {
+ SILC_LOG_DEBUG(("Bad payload length"));
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ len2 = len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 2;
+ silc_buffer_pull(buffer, len);
+
+ /* Copy cookie from payload */
+ payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN,
+ sizeof(unsigned char));
+ payload->cookie_len = SILC_SKE_COOKIE_LEN;
+ memcpy(payload->cookie, buf, SILC_SKE_COOKIE_LEN);
+ memset(buf, 0, sizeof(buf));
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, payload->ke_grp_len),
+ SILC_STR_UI_SHORT(&payload->pkcs_alg_len),
+ SILC_STR_END);
+
+ if (payload->pkcs_alg_len < 1) {
+ SILC_LOG_DEBUG(("Bad payload length"));
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ len2 += len = payload->ke_grp_len + 2;
+ silc_buffer_pull(buffer, len);
+
+ /* Copy KE groups from payload */
+ payload->ke_grp_list = silc_calloc(payload->ke_grp_len + 1,
+ sizeof(unsigned char));
+ memcpy(payload->ke_grp_list, buf, payload->ke_grp_len);
+ memset(buf, 0, sizeof(buf));
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, payload->pkcs_alg_len),
+ SILC_STR_UI_SHORT(&payload->enc_alg_len),
+ SILC_STR_END);
+
+ if (payload->enc_alg_len < 1) {
+ SILC_LOG_DEBUG(("Bad payload length"));
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ len2 += len = payload->pkcs_alg_len + 2;
+ silc_buffer_pull(buffer, len);
+
+ /* Copy PKCS algs from payload */
+ payload->pkcs_alg_list = silc_calloc(payload->pkcs_alg_len + 1,
+ sizeof(unsigned char));
+ memcpy(payload->pkcs_alg_list, buf, payload->pkcs_alg_len);
+ memset(buf, 0, sizeof(buf));
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, payload->enc_alg_len),
+ SILC_STR_UI_SHORT(&payload->hash_alg_len),
+ SILC_STR_END);
+
+ if (payload->hash_alg_len < 1) {
+ SILC_LOG_DEBUG(("Bad payload length"));
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ len2 += len = payload->enc_alg_len + 2;
+ silc_buffer_pull(buffer, len);
+
+ /* Copy encryption algs from payload */
+ payload->enc_alg_list = silc_calloc(payload->enc_alg_len + 1,
+ sizeof(unsigned char));
+ memcpy(payload->enc_alg_list, buf, payload->enc_alg_len);
+ memset(buf, 0, sizeof(buf));
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, payload->hash_alg_len),
+ SILC_STR_UI_SHORT(&payload->comp_alg_len),
+ SILC_STR_END);
+
+ len2 += len = payload->hash_alg_len + 2;
+ silc_buffer_pull(buffer, len);
+
+ /* Copy hash algs from payload */
+ payload->hash_alg_list = silc_calloc(payload->hash_alg_len + 1,
+ sizeof(unsigned char));
+ memcpy(payload->hash_alg_list, buf, payload->hash_alg_len);
+ memset(buf, 0, sizeof(buf));
+
+ if (payload->comp_alg_len) {
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, payload->comp_alg_len),
+ SILC_STR_END);
+
+ /* Copy compression algs from payload */
+ payload->comp_alg_list = silc_calloc(payload->comp_alg_len + 1,
+ sizeof(unsigned char));
+ memcpy(payload->comp_alg_list, buf, payload->comp_alg_len);
+ memset(buf, 0, sizeof(buf));
+ }
+
+ silc_buffer_push(buffer, len2);
+
+ /* Return the payload */
+ *return_payload = payload;
+
+ return SILC_SKE_STATUS_OK;
+
+ err:
+ silc_ske_payload_start_free(payload);
+
+ return status;
+}
+
+/* Free's Start Payload */
+
+void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
+{
+ if (payload) {
+ if (payload->cookie)
+ silc_free(payload->cookie);
+ if (payload->ke_grp_list)
+ silc_free(payload->ke_grp_list);
+ if (payload->pkcs_alg_list)
+ silc_free(payload->pkcs_alg_list);
+ if (payload->enc_alg_list)
+ silc_free(payload->enc_alg_list);
+ if (payload->hash_alg_list)
+ silc_free(payload->hash_alg_list);
+ if (payload->comp_alg_list)
+ silc_free(payload->comp_alg_list);
+ silc_free(payload);
+ }
+}
+
+/* Encodes Key Exchange 1 Payload into a SILC Buffer to be sent
+ to the other end. */
+
+SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
+ SilcSKEOnePayload *payload,
+ SilcBuffer *return_buffer)
+{
+ SilcBuffer buf;
+ unsigned char *e_str;
+ unsigned short e_len;
+
+ SILC_LOG_DEBUG(("Encoding KE 1 Payload"));
+
+ if (!payload)
+ return SILC_SKE_STATUS_ERROR;
+
+ /* Encode the integer into HEX string */
+ e_len = silc_mp_sizeinbase(&payload->e, 16);
+ e_str = silc_calloc(e_len + 1, sizeof(unsigned char));
+ silc_mp_get_str(e_str, 16, &payload->e);
+
+ /* Allocate channel payload buffer. The length of the buffer
+ is 2 + e. */
+ buf = silc_buffer_alloc(e_len + 2);
+ if (!buf) {
+ SILC_LOG_ERROR(("Could not allocate encode buffer"));
+ return SILC_SKE_STATUS_ERROR;
+ }
+
+ silc_buffer_pull_tail(buf, e_len + 2);
+
+ /* Encode the payload */
+ silc_buffer_format(buf,
+ SILC_STR_UI_SHORT(e_len + 2),
+ SILC_STR_UI_XNSTRING(e_str, e_len),
+ SILC_STR_END);
+
+ /* Return encoded buffer */
+ *return_buffer = buf;
+
+ memset(e_str, 'F', e_len);
+ silc_free(e_str);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Parses the Key Exchange 1 Payload. Parsed data is returned
+ to allocated payload structure. */
+
+SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
+ SilcBuffer buffer,
+ SilcSKEOnePayload **return_payload)
+{
+ SilcSKEOnePayload *payload;
+ SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
+ unsigned short e_len;
+
+ SILC_LOG_DEBUG(("Decoding Key Exchange 1 Payload"));
+
+ SILC_LOG_HEXDUMP(("KE 1 Payload"), buffer->data, buffer->len);
+
+ payload = silc_calloc(1, sizeof(*payload));
+
+ memset(buf, 0, sizeof(buf));
+
+ /* Parse the payload */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&e_len),
+ SILC_STR_END);
+
+ if (e_len < 1) {
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ if (e_len != buffer->len) {
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ /* Length includes the length field length as well. Remove it. */
+ e_len -= 2;
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(NULL),
+ SILC_STR_UI_XNSTRING(&buf, e_len),
+ SILC_STR_END);
+
+ /* Decode the HEX string to integer */
+ silc_mp_init(&payload->e);
+ silc_mp_set_str(&payload->e, buf, 16);
+ memset(buf, 0, sizeof(buf));
+
+ /* Return the payload */
+ *return_payload = payload;
+
+ return SILC_SKE_STATUS_OK;
+
+ err:
+ silc_free(payload);
+
+ return status;
+}
+
+/* Free's KE1 Payload */
+
+void silc_ske_payload_one_free(SilcSKEOnePayload *payload)
+{
+ if (payload) {
+ silc_mp_clear(&payload->e);
+ silc_free(payload);
+ }
+}
+
+/* Encodes Key Exchange 2 Payload into a SILC Buffer to be sent
+ to the other end. */
+
+SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
+ SilcSKETwoPayload *payload,
+ SilcBuffer *return_buffer)
+{
+ SilcBuffer buf;
+ unsigned char *f_str;
+ unsigned int f_len;
+ unsigned int len;
+
+ SILC_LOG_DEBUG(("Encoding KE 2 Payload"));
+
+ if (!payload)
+ return SILC_SKE_STATUS_ERROR;
+
+ /* Encode the integer into HEX string */
+ f_len = silc_mp_sizeinbase(&payload->f, 16);
+ f_str = silc_calloc(f_len + 1, sizeof(unsigned char));
+ silc_mp_get_str(f_str, 16, &payload->f);
+
+ /* Allocate channel payload buffer. The length of the buffer
+ is 2 + 2 + public key + 2 + f + 2 + signature. */
+ len = payload->pk_len + 2 + 2 + f_len + 2 + payload->sign_len + 2;
+ buf = silc_buffer_alloc(len);
+ if (!buf) {
+ SILC_LOG_ERROR(("Could not allocate encode buffer"));
+ return SILC_SKE_STATUS_ERROR;
+ }
+
+ silc_buffer_pull_tail(buf, len);
+
+ /* Encode the payload */
+ silc_buffer_format(buf,
+ SILC_STR_UI_SHORT(payload->pk_len + 4),
+ SILC_STR_UI_SHORT(payload->pk_type),
+ SILC_STR_UI_XNSTRING(payload->pk_data,
+ payload->pk_len),
+ SILC_STR_UI_SHORT(f_len + 2),
+ SILC_STR_UI_XNSTRING(f_str, f_len),
+ SILC_STR_UI_SHORT(payload->sign_len + 2),
+ SILC_STR_UI_XNSTRING(payload->sign_data,
+ payload->sign_len),
+ SILC_STR_END);
+
+ /* Return encoded buffer */
+ *return_buffer = buf;
+
+ memset(f_str, 'F', f_len);
+ silc_free(f_str);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Parses the Key Exchange 2 Payload. Parsed data is returned
+ to allocated payload structure. */
+
+SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
+ SilcBuffer buffer,
+ SilcSKETwoPayload **return_payload)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
+ SilcSKETwoPayload *payload;
+ unsigned short f_len;
+ unsigned int tot_len = 0, len2;
+
+ SILC_LOG_DEBUG(("Decoding Key Exchange 2 Payload"));
+
+ SILC_LOG_HEXDUMP(("KE 2 Payload"), buffer->data, buffer->len);
+
+ payload = silc_calloc(1, sizeof(*payload));
+ memset(buf, 0, sizeof(buf));
+
+ len2 = buffer->len;
+
+ /* Parse the payload */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&payload->pk_len),
+ SILC_STR_UI_SHORT(&payload->pk_type),
+ SILC_STR_END);
+
+ if (payload->pk_len < 5) {
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ tot_len += payload->pk_len;
+
+ payload->pk_len -= 4;
+ silc_buffer_pull(buffer, 4);
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, payload->pk_len),
+ SILC_STR_UI_SHORT(&f_len),
+ SILC_STR_END);
+
+ if (f_len < 3) {
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ tot_len += f_len;
+
+ payload->pk_data = silc_calloc(payload->pk_len + 1,
+ sizeof(unsigned char));
+ memcpy(payload->pk_data, buf, payload->pk_len);
+ memset(buf, 0, sizeof(buf));
+
+ f_len -= 2;
+ silc_buffer_pull(buffer, payload->pk_len + 2);
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, f_len),
+ SILC_STR_UI_SHORT(&payload->sign_len),
+ SILC_STR_END);
+
+ if (payload->sign_len < 3) {
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ tot_len += payload->sign_len;
+
+ if (tot_len != len2) {
+ status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+ goto err;
+ }
+
+ /* Decode the HEX string to integer */
+ silc_mp_init(&payload->f);
+ silc_mp_set_str(&payload->f, buf, 16);
+ memset(buf, 0, sizeof(buf));
+
+ payload->sign_len -= 2;
+ silc_buffer_pull(buffer, f_len + 2);
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING(&buf, payload->sign_len),
+ SILC_STR_END);
+
+ payload->sign_data = silc_calloc(payload->sign_len + 1,
+ sizeof(unsigned char));
+ memcpy(payload->sign_data, buf, payload->sign_len);
+ memset(buf, 0, sizeof(buf));
+
+ /* Return the payload */
+ *return_payload = payload;
+
+ return SILC_SKE_STATUS_OK;
+
+ err:
+ if (payload->pk_data)
+ silc_free(payload->pk_data);
+ if (payload->sign_data)
+ silc_free(payload->sign_data);
+ silc_free(payload);
+
+ return status;
+}
+
+/* Free's KE2 Payload */
+
+void silc_ske_payload_two_free(SilcSKETwoPayload *payload)
+{
+ if (payload) {
+ if (payload->pk_data)
+ silc_free(payload->pk_data);
+ if (payload->sign_data)
+ silc_free(payload->sign_data);
+ silc_mp_clear(&payload->f);
+ silc_free(payload);
+ }
+}
--- /dev/null
+/*
+
+ payload.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef PAYLOAD_H
+#define PAYLOAD_H
+
+#include "silcske_status.h"
+#include "payload_internal.h"
+
+/* Prototypes */
+SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
+ SilcSKEStartPayload *payload,
+ SilcBuffer *return_buffer);
+SilcSKEStatus
+silc_ske_payload_start_decode(SilcSKE ske,
+ SilcBuffer buffer,
+ SilcSKEStartPayload **return_payload);
+void silc_ske_payload_start_free(SilcSKEStartPayload *payload);
+SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
+ SilcSKEOnePayload *payload,
+ SilcBuffer *return_buffer);
+SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
+ SilcBuffer buffer,
+ SilcSKEOnePayload **return_payload);
+void silc_ske_payload_one_free(SilcSKEOnePayload *payload);
+SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
+ SilcSKETwoPayload *payload,
+ SilcBuffer *return_buffer);
+SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
+ SilcBuffer buffer,
+ SilcSKETwoPayload **return_payload);
+void silc_ske_payload_two_free(SilcSKETwoPayload *payload);
+
+#endif
--- /dev/null
+/*
+
+ payload_internal.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef PAYLOAD_INTERNAL_H
+#define PAYLOAD_INTERNAL_H
+
+/* SILC Key Exchange Start Payload */
+typedef struct {
+ unsigned char flags;
+ unsigned int len;
+
+ unsigned char *cookie;
+ unsigned short cookie_len;
+
+ unsigned short ke_grp_len;
+ unsigned char *ke_grp_list;
+
+ unsigned short pkcs_alg_len;
+ unsigned char *pkcs_alg_list;
+
+ unsigned short enc_alg_len;
+ unsigned char *enc_alg_list;
+
+ unsigned short hash_alg_len;
+ unsigned char *hash_alg_list;
+
+ unsigned short comp_alg_len;
+ unsigned char *comp_alg_list;
+} SilcSKEStartPayload;
+
+/* SILC Key Exchange 1 Payload */
+typedef struct {
+ SilcInt e;
+} SilcSKEOnePayload;
+
+/* SILC Key Exchange 2 Payload */
+typedef struct {
+ unsigned short pk_len;
+ unsigned char *pk_data;
+ unsigned short pk_type;
+
+ SilcInt f;
+
+ unsigned short sign_len;
+ unsigned char *sign_data;
+} SilcSKETwoPayload;
+
+#endif
--- /dev/null
+/*
+
+ silcske.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1 2000/06/27 11:36:56 priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "payload_internal.h"
+#include "groups_internal.h"
+
+/* Allocates new SKE object. */
+
+SilcSKE silc_ske_alloc()
+{
+ SilcSKE ske;
+
+ SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
+
+ ske = silc_calloc(1, sizeof(*ske));
+ if (!ske) {
+ SILC_LOG_ERROR(("Could not allocate new SKE object"));
+ return NULL;
+ }
+
+ return ske;
+}
+
+/* Free's SKE object. */
+
+void silc_ske_free(SilcSKE ske)
+{
+ SILC_LOG_DEBUG(("Freeing Key Exchange object"));
+
+ if (ske) {
+ /* Free start payload */
+ if (ske->start_payload)
+ silc_ske_payload_start_free(ske->start_payload);
+
+ /* Free KE1 payload */
+ if (ske->ke1_payload)
+ silc_ske_payload_one_free(ske->ke1_payload);
+
+ /* Free KE2 payload */
+ if (ske->ke2_payload)
+ silc_ske_payload_two_free(ske->ke2_payload);
+
+ /* Free rest */
+ if (ske->prop) {
+ if (ske->prop->group)
+ silc_free(ske->prop->group);
+ if (ske->prop->pkcs)
+ silc_pkcs_free(ske->prop->pkcs);
+ if (ske->prop->cipher)
+ silc_cipher_free(ske->prop->cipher);
+ if (ske->prop->hash)
+ silc_hash_free(ske->prop->hash);
+ silc_free(ske->prop);
+ }
+ if (ske->start_payload_copy)
+ silc_buffer_free(ske->start_payload_copy);
+ if (ske->pk)
+ silc_free(ske->pk);
+ silc_mp_clear(&ske->x);
+ silc_mp_clear(&ske->KEY);
+ if (ske->hash)
+ silc_free(ske->hash);
+ silc_free(ske);
+ }
+}
+
+/* Starts the SILC Key Exchange protocol for initiator. The connection
+ to the remote end must be established before calling this function
+ and the connecting socket must be sent as argument. This function
+ creates the Key Exchange Start Paload which includes all our
+ configured security properties. This payload is then sent to the
+ remote end for further processing. This payload must be sent as
+ argument to the function, however, it must not be encoded
+ already, it is done by this function.
+
+ The packet sending is done by calling a callback function. Caller
+ must provide a routine to send the packet. */
+
+SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ SilcSKEStartPayload *start_payload,
+ SilcSKESendPacketCb send_packet,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ ske->sock = sock;
+ ske->rng = rng;
+
+ /* Encode the payload */
+ status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
+
+ /* Take a copy of the payload buffer for future use. It is used to
+ compute the HASH value. */
+ ske->start_payload_copy = silc_buffer_copy(payload_buf);
+
+ /* Send the packet. */
+ if (send_packet)
+ (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
+
+ silc_buffer_free(payload_buf);
+
+ return status;
+}
+
+/* Function called after ske_initiator_start fuction. This receives
+ the remote ends Key Exchange Start payload which includes the
+ security properties selected by the responder from our payload
+ sent in the silc_ske_initiator_start function. */
+
+SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
+ SilcBuffer start_payload,
+ SilcSKECb callback,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEStartPayload *payload;
+ SilcSKESecurityProperties prop;
+ SilcSKEDiffieHellmanGroup group;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decode the payload */
+ status = silc_ske_payload_start_decode(ske, start_payload, &payload);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
+
+ /* Take the selected security properties into use while doing
+ the key exchange. This is used only while doing the key
+ exchange. The same data is returned to upper levels by calling
+ the callback function. */
+ ske->prop = prop = silc_calloc(1, sizeof(*prop));
+ prop->flags = payload->flags;
+ status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ prop->group = group;
+
+ if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_PKCS;
+ goto err;
+ }
+
+ if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
+ goto err;
+ }
+
+ if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+ goto err;
+ }
+
+ ske->start_payload = payload;
+
+ /* Return the received payload by calling the callback function. */
+ if (callback)
+ (*callback)(ske, context);
+
+ return status;
+
+ err:
+ if (payload)
+ silc_ske_payload_start_free(payload);
+
+ silc_free(group);
+
+ if (prop->pkcs)
+ silc_pkcs_free(prop->pkcs);
+ if (prop->cipher)
+ silc_cipher_free(prop->cipher);
+ if (prop->hash)
+ silc_hash_free(prop->hash);
+ silc_free(prop);
+ ske->prop = NULL;
+
+ if (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
+
+ return status;
+}
+
+/* This function creates random number x, such that 1 < x < q and
+ computes e = g ^ x mod p and sends the result to the remote end in
+ Key Exchange 1 Payload. */
+
+SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+ SilcSKESendPacketCb send_packet,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
+ SilcInt x, e;
+ SilcSKEOnePayload *payload;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Create the random number x, 1 < x < q. */
+ silc_mp_init(&x);
+ status =
+ silc_ske_create_rnd(ske, ske->prop->group->group_order,
+ silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
+ &x);
+ if (status != SILC_SKE_STATUS_OK) {
+ silc_mp_clear(&x);
+ return status;
+ }
+
+ SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
+
+ /* Do the Diffie Hellman computation, e = g ^ x mod p */
+ silc_mp_init(&e);
+ silc_mp_powm(&e, &ske->prop->group->generator, &x,
+ &ske->prop->group->group);
+
+ /* Encode the result to Key Exchange 1 Payload. */
+ payload = silc_calloc(1, sizeof(*payload));
+ payload->e = e;
+ status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
+ if (status != SILC_SKE_STATUS_OK) {
+ silc_mp_clear(&x);
+ silc_mp_clear(&e);
+ silc_free(payload);
+ return status;
+ }
+
+ ske->ke1_payload = payload;
+ ske->x = x;
+
+ /* Send the packet. */
+ if (send_packet)
+ (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
+
+ silc_buffer_free(payload_buf);
+
+ return status;
+}
+
+/* Receives Key Exchange 2 Payload from responder consisting responders
+ public key, f, and signature. This function verifies the public key,
+ computes the secret shared key and verifies the signature. */
+
+SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+ SilcBuffer ke2_payload,
+ SilcSKECb callback,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKETwoPayload *payload;
+ SilcInt KEY;
+ unsigned char hash[32];
+ unsigned int hash_len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decode the payload */
+ status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
+ ske->ke2_payload = payload;
+
+ SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
+
+ /* Compute the shared secret key */
+ silc_mp_init(&KEY);
+ silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
+ ske->KEY = KEY;
+
+ SILC_LOG_DEBUG(("Verifying public key"));
+
+ /* Verify the public key */ /* XXX */
+ status = silc_ske_verify_public_key(ske, payload->pk_data,
+ payload->pk_len);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ SILC_LOG_DEBUG(("Public key is authentic"));
+
+ /* Compute the hash value */
+ status = silc_ske_make_hash(ske, hash, &hash_len);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
+ memcpy(ske->hash, hash, hash_len);
+ ske->hash_len = hash_len;
+
+ SILC_LOG_DEBUG(("Verifying signature"));
+
+ /* Verify signature */
+ silc_pkcs_set_public_key(ske->prop->pkcs, payload->pk_data, payload->pk_len);
+ if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
+ payload->sign_data, payload->sign_len,
+ hash, hash_len) == FALSE) {
+
+ SILC_LOG_DEBUG(("Signature don't match"));
+
+ status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
+ goto err;
+ }
+
+ SILC_LOG_DEBUG(("Signature is Ok"));
+
+ memset(hash, 'F', hash_len);
+
+ /* Call the callback. */
+ if (callback)
+ (*callback)(ske, context);
+
+ return status;
+
+ err:
+ memset(hash, 'F', hash_len);
+ silc_ske_payload_two_free(payload);
+
+ silc_mp_clear(&ske->KEY);
+
+ if (ske->hash) {
+ memset(ske->hash, 'F', hash_len);
+ silc_free(ske->hash);
+ ske->hash = NULL;
+ }
+
+ if (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
+
+ return status;
+}
+
+/* Starts Key Exchange protocol for responder. Responder receives
+ Key Exchange Start Payload from initiator consisting of all the
+ security properties the initiator supports. This function decodes
+ the payload and parses the payload further and selects the right
+ security properties. */
+
+SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ SilcBuffer start_payload,
+ SilcSKECb callback,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ ske->sock = sock;
+ ske->rng = rng;
+
+ /* Decode the payload */
+ status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
+
+ /* Take a copy of the payload buffer for future use. It is used to
+ compute the HASH value. */
+ ske->start_payload_copy = silc_buffer_copy(start_payload);
+
+ /* Parse and select the security properties from the payload */
+ payload = silc_calloc(1, sizeof(*payload));
+ status = silc_ske_select_security_properties(ske, payload, remote_payload);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ ske->start_payload = payload;
+
+ /* Call the callback function. */
+ if (callback)
+ (*callback)(ske, context);
+
+ return status;
+
+ err:
+ if (remote_payload)
+ silc_ske_payload_start_free(remote_payload);
+ if (payload)
+ silc_free(payload);
+
+ if (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
+
+ return status;
+}
+
+/* The selected security properties from the initiator payload is now
+ encoded into Key Exchange Start Payload and sent to the initiator. */
+
+SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
+ SilcSKEStartPayload *start_payload,
+ SilcSKESendPacketCb send_packet,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
+ SilcSKESecurityProperties prop;
+ SilcSKEDiffieHellmanGroup group;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate security properties from the payload. These are allocated
+ only for this negotiation and will be free'd after KE is over. */
+ ske->prop = prop = silc_calloc(1, sizeof(*prop));
+ prop->flags = start_payload->flags;
+ status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ prop->group = group;
+
+ if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
+ &prop->pkcs) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_PKCS;
+ goto err;
+ }
+
+ if (silc_cipher_alloc(start_payload->enc_alg_list,
+ &prop->cipher) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
+ goto err;
+ }
+
+ if (silc_hash_alloc(start_payload->hash_alg_list,
+ &prop->hash) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+ goto err;
+ }
+
+ /* Encode the payload */
+ status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ /* Send the packet. */
+ if (send_packet)
+ (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
+
+ silc_buffer_free(payload_buf);
+
+ return status;
+
+ err:
+ silc_free(group);
+
+ if (prop->pkcs)
+ silc_pkcs_free(prop->pkcs);
+ if (prop->cipher)
+ silc_cipher_free(prop->cipher);
+ if (prop->hash)
+ silc_hash_free(prop->hash);
+ silc_free(prop);
+ ske->prop = NULL;
+
+ if (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
+
+ return status;
+}
+
+/* This function receives the Key Exchange 1 Payload from the initiator.
+ After processing the payload this then selects random number x,
+ such that 1 < x < q and computes f = g ^ x mod p. This then puts
+ the result f to a Key Exchange 2 Payload which is later processed
+ in ske_responder_finish function. The callback function should
+ not touch the payload (it should merely call the ske_responder_finish
+ function). */
+
+SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
+ SilcBuffer ke1_payload,
+ SilcSKECb callback,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEOnePayload *one_payload;
+ SilcSKETwoPayload *two_payload;
+ SilcInt x, f;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decode Key Exchange 1 Payload */
+ status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
+
+ /* Create the random number x, 1 < x < q. */
+ silc_mp_init(&x);
+ status =
+ silc_ske_create_rnd(ske, ske->prop->group->group_order,
+ silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
+ &x);
+ if (status != SILC_SKE_STATUS_OK) {
+ silc_mp_clear(&x);
+ return status;
+ }
+
+ SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
+
+ /* Do the Diffie Hellman computation, f = g ^ x mod p */
+ silc_mp_init(&f);
+ silc_mp_powm(&f, &ske->prop->group->generator, &x,
+ &ske->prop->group->group);
+
+ /* Save the results for later processing */
+ two_payload = silc_calloc(1, sizeof(*two_payload));
+ two_payload->f = f;
+ ske->x = x;
+ ske->ke1_payload = one_payload;
+ ske->ke2_payload = two_payload;
+
+ /* Call the callback. */
+ if (callback)
+ (*callback)(ske, context);
+
+ return status;
+}
+
+/* This function computes the secret shared key KEY = e ^ x mod p, and,
+ a hash value to be signed and sent to the other end. This then
+ encodes Key Exchange 2 Payload and sends it to the other end. */
+
+SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
+ unsigned char *pk,
+ unsigned int pk_len,
+ unsigned char *prv,
+ unsigned int prv_len,
+ SilcSKEPKType pk_type,
+ SilcSKESendPacketCb send_packet,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
+ SilcInt KEY;
+ unsigned char hash[32], sign[256];
+ unsigned int hash_len, sign_len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
+
+ /* Compute the shared secret key */
+ silc_mp_init(&KEY);
+ silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
+ &ske->prop->group->group);
+ ske->KEY = KEY;
+
+ SILC_LOG_DEBUG(("Getting public key"));
+
+ /* Get the public key */
+ ske->ke2_payload->pk_data = silc_calloc(pk_len, sizeof(unsigned char));
+ memcpy(ske->ke2_payload->pk_data, pk, pk_len);
+ ske->ke2_payload->pk_len = pk_len;
+ ske->ke2_payload->pk_type = pk_type;
+
+ SILC_LOG_DEBUG(("Computing HASH value"));
+
+ /* Compute the hash value */
+ memset(hash, 0, sizeof(hash));
+ status = silc_ske_make_hash(ske, hash, &hash_len);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
+ memcpy(ske->hash, hash, hash_len);
+ ske->hash_len = hash_len;
+
+ SILC_LOG_DEBUG(("Signing HASH value"));
+
+ /* Sign the hash value */
+ silc_pkcs_set_private_key(ske->prop->pkcs, prv, prv_len);
+ ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
+ hash, hash_len,
+ sign, &sign_len);
+ ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
+ memcpy(ske->ke2_payload->sign_data, sign, sign_len);
+ memset(sign, 0, sizeof(sign));
+ ske->ke2_payload->sign_len = sign_len;
+
+ /* Encode the Key Exchange 2 Payload */
+ status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
+ &payload_buf);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ /* Send the packet. */
+ if (send_packet)
+ (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
+
+ silc_buffer_free(payload_buf);
+
+ return status;
+
+ err:
+ silc_mp_clear(&ske->KEY);
+ silc_ske_payload_two_free(ske->ke2_payload);
+
+ if (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
+
+ return status;
+}
+
+/* The Key Exchange protocol is ended by calling this function. This
+ must not be called until the keys are processed like the protocol
+ defines. This function is for both initiator and responder. */
+
+SilcSKEStatus silc_ske_end(SilcSKE ske,
+ SilcSKESendPacketCb send_packet,
+ void *context)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer packet;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ packet = silc_buffer_alloc(1);
+ packet->len = 0;
+
+ if (send_packet)
+ (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
+
+ return status;
+}
+
+/* Aborts the Key Exchange protocol. This is called if error occurs
+ while performing the protocol. The status argument is the error
+ status and it is sent to the remote end. */
+
+SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
+ SilcSKESendPacketCb send_packet,
+ void *context)
+{
+ SilcBuffer packet;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ packet = silc_buffer_alloc(4);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(status),
+ SILC_STR_END);
+
+ if (send_packet)
+ (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
+
+ silc_buffer_free(packet);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Assembles security properties to Key Exchange Start Payload to be
+ sent to the remote end. This checks system wide (SILC system, that is)
+ settings and chooses from those. However, if other properties
+ should be used this function is easy to replace by another function,
+ as, this function is called by the caller of the protocol and not
+ by the protocol itself. */
+
+SilcSKEStatus
+silc_ske_assemble_security_properties(SilcSKE ske,
+ SilcSKEStartPayload **return_payload)
+{
+ SilcSKEStartPayload *rp;
+
+ SILC_LOG_DEBUG(("Assembling KE Start Payload"));
+
+ rp = silc_calloc(1, sizeof(*rp));
+
+ /* XXX */
+ /* Set flags */
+ rp->flags = 0;
+
+ /* XXX */
+ /* Cookie */
+ rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
+ rp->cookie_len = SILC_SKE_COOKIE_LEN;
+ memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
+
+ /* Get supported Key Exhange groups */
+ rp->ke_grp_list = silc_ske_get_supported_groups();
+ rp->ke_grp_len = strlen(rp->ke_grp_list);
+
+ /* Get supported PKCS algorithms */
+ rp->pkcs_alg_list = silc_pkcs_get_supported();
+ rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
+
+ /* Get supported encryption algorithms */
+ rp->enc_alg_list = silc_cipher_get_supported();
+ rp->enc_alg_len = strlen(rp->enc_alg_list);
+
+ /* Get supported hash algorithms */
+ rp->hash_alg_list = silc_hash_get_supported();
+ rp->hash_alg_len = strlen(rp->hash_alg_list);
+
+ /* XXX */
+ /* Get supported compression algorithms */
+ rp->comp_alg_list = "";
+ rp->comp_alg_len = 0;
+
+ rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+ 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
+ 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
+ 2 + rp->comp_alg_len;
+
+ *return_payload = rp;
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Selects the supported security properties from the remote end's Key
+ Exchange Start Payload. */
+
+SilcSKEStatus
+silc_ske_select_security_properties(SilcSKE ske,
+ SilcSKEStartPayload *payload,
+ SilcSKEStartPayload *remote_payload)
+{
+ SilcSKEStartPayload *rp;
+ char *cp;
+ int len;
+
+ SILC_LOG_DEBUG(("Parsing KE Start Payload"));
+
+ rp = remote_payload;
+
+ /* Flags are returned unchanged. */
+ payload->flags = rp->flags;
+
+ /* XXX Cookie check?? */
+ payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
+ payload->cookie_len = SILC_SKE_COOKIE_LEN;
+ memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
+
+ /* Get supported Key Exchange groups */
+ cp = rp->ke_grp_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
+
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
+
+ SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
+
+ if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
+ SILC_LOG_DEBUG(("Found KE group `%s'", item));
+
+ payload->ke_grp_len = len;
+ payload->ke_grp_list = item;
+ break;
+ }
+
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
+
+ if (item)
+ silc_free(item);
+ }
+
+ if (!payload->ke_grp_len && !payload->ke_grp_list) {
+ SILC_LOG_DEBUG(("Could not find supported KE group"));
+ silc_free(payload);
+ return SILC_SKE_STATUS_UNKNOWN_GROUP;
+ }
+ } else {
+
+ if (!rp->ke_grp_len) {
+ SILC_LOG_DEBUG(("KE group not defined in payload"));
+ silc_free(payload);
+ return SILC_SKE_STATUS_BAD_PAYLOAD;
+ }
+
+ SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
+ SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
+
+ payload->ke_grp_len = rp->ke_grp_len;
+ payload->ke_grp_list = strdup(rp->ke_grp_list);
+ }
+
+ /* Get supported PKCS algorithms */
+ cp = rp->pkcs_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
+
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
+
+ SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
+
+ if (silc_pkcs_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
+
+ payload->pkcs_alg_len = len;
+ payload->pkcs_alg_list = item;
+ break;
+ }
+
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
+
+ if (item)
+ silc_free(item);
+ }
+
+ if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
+ SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_UNKNOWN_PKCS;
+ }
+ } else {
+
+ if (!rp->pkcs_alg_len) {
+ SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_BAD_PAYLOAD;
+ }
+
+ SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
+ SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
+
+ payload->pkcs_alg_len = rp->pkcs_alg_len;
+ payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
+ }
+
+ /* Get supported encryption algorithms */
+ cp = rp->enc_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
+
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
+
+ SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
+
+ if (silc_cipher_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
+
+ payload->enc_alg_len = len;
+ payload->enc_alg_list = item;
+ break;
+ }
+
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
+
+ if (item)
+ silc_free(item);
+ }
+
+ if (!payload->enc_alg_len && !payload->enc_alg_list) {
+ SILC_LOG_DEBUG(("Could not find supported encryption alg"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload->pkcs_alg_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_UNKNOWN_CIPHER;
+ }
+ } else {
+
+ if (!rp->enc_alg_len) {
+ SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload->pkcs_alg_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_BAD_PAYLOAD;
+ }
+
+ SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
+ rp->enc_alg_list));
+
+ payload->enc_alg_len = rp->enc_alg_len;
+ payload->enc_alg_list = strdup(rp->enc_alg_list);
+ }
+
+ /* Get supported hash algorithms */
+ cp = rp->hash_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
+
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
+
+ SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
+
+ if (silc_hash_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found hash alg `%s'", item));
+
+ payload->hash_alg_len = len;
+ payload->hash_alg_list = item;
+ break;
+ }
+
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
+
+ if (item)
+ silc_free(item);
+ }
+
+ if (!payload->hash_alg_len && !payload->hash_alg_list) {
+ SILC_LOG_DEBUG(("Could not find supported hash alg"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload->pkcs_alg_list);
+ silc_free(payload->enc_alg_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+ }
+ } else {
+
+ if (!rp->hash_alg_len) {
+ SILC_LOG_DEBUG(("Hash alg not defined in payload"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload->pkcs_alg_list);
+ silc_free(payload->enc_alg_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_BAD_PAYLOAD;
+ }
+
+ SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
+ rp->hash_alg_list));
+
+ payload->hash_alg_len = rp->hash_alg_len;
+ payload->hash_alg_list = strdup(rp->hash_alg_list);
+ }
+
+#if 0
+ /* Get supported compression algorithms */
+ cp = rp->hash_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
+
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
+
+ SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
+
+ if (silc_hash_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found hash alg `%s'", item));
+
+ payload->hash_alg_len = len;
+ payload->hash_alg_list = item;
+ break;
+ }
+
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
+
+ if (item)
+ silc_free(item);
+ }
+
+ if (!payload->hash_alg_len && !payload->hash_alg_list) {
+ SILC_LOG_DEBUG(("Could not find supported hash alg"));
+ silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
+ silc_free(payload->ke_grp_list);
+ silc_free(payload->pkcs_alg_list);
+ silc_free(payload->enc_alg_list);
+ silc_free(payload);
+ return;
+ }
+ } else {
+
+ }
+#endif
+
+ payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+ 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
+ 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
+ 2 + payload->comp_alg_len;
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Creates random number such that 1 < rnd < n and at most length
+ of len bits. The rnd sent as argument must be initialized. */
+
+SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
+ unsigned int len,
+ SilcInt *rnd)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ unsigned char *string;
+
+ SILC_LOG_DEBUG(("Creating random number"));
+
+ /* Get the random number as string */
+ string = silc_rng_get_rn_string(ske->rng, (len / 8));
+
+ /* Decode the string into a MP integer */
+ silc_mp_set_str(rnd, string, 16);
+ silc_mp_mod_2exp(rnd, rnd, len);
+
+ /* Checks */
+ if (silc_mp_cmp_ui(rnd, 1) < 0)
+ status = SILC_SKE_STATUS_ERROR;
+
+ if (silc_mp_cmp(rnd, &n) >= 0)
+ status = SILC_SKE_STATUS_ERROR;
+
+ memset(string, 'F', (len / 8));
+ silc_free(string);
+
+ return status;
+}
+
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske,
+ unsigned char *pubkey,
+ unsigned int pubkey_len)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+
+ return status;
+}
+
+/* Creates a hash value HASH as defined in the SKE protocol. */
+
+SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
+ unsigned char *return_hash,
+ unsigned int *return_hash_len)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer buf;
+ unsigned char *e, *f, *KEY;
+ unsigned int e_len, f_len, KEY_len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
+ e = silc_calloc(e_len + 1, sizeof(unsigned char));
+ silc_mp_get_str(e, 16, &ske->ke1_payload->e);
+
+ f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
+ f = silc_calloc(f_len + 1, sizeof(unsigned char));
+ silc_mp_get_str(f, 16, &ske->ke2_payload->f);
+
+ KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
+ KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
+ silc_mp_get_str(KEY, 16, &ske->KEY);
+
+ buf = silc_buffer_alloc(ske->start_payload_copy->len +
+ ske->pk_len + e_len + f_len + KEY_len);
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+ /* Format the buffer used to compute the hash value */
+ silc_buffer_format(buf,
+ SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+ ske->start_payload_copy->len),
+ SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
+ SILC_STR_UI_XNSTRING(e, e_len),
+ SILC_STR_UI_XNSTRING(f, f_len),
+ SILC_STR_UI_XNSTRING(KEY, KEY_len),
+ SILC_STR_END);
+
+#if 0
+ SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
+#endif
+
+ /* Make the hash */
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
+ *return_hash_len = ske->prop->hash->hash->hash_len;
+
+ SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
+
+ silc_buffer_free(buf);
+ memset(e, 0, e_len);
+ memset(f, 0, f_len);
+ memset(KEY, 0, KEY_len);
+ silc_free(e);
+ silc_free(f);
+ silc_free(KEY);
+
+ return status;
+}
+
+/* Processes negotiated key material as protocol specifies. This returns
+ the actual keys to be used in the SILC. */
+
+SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
+ unsigned int req_iv_len,
+ unsigned int req_enc_key_len,
+ unsigned int req_hmac_key_len,
+ SilcSKEKeyMaterial *key)
+{
+ int i, klen;
+ SilcBuffer buf;
+ SilcInt tmp;
+ unsigned char *tmpbuf;
+ unsigned char hash[32];
+ unsigned int hash_len = ske->prop->hash->hash->hash_len;
+ unsigned int enc_key_len = req_enc_key_len / 8;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ silc_mp_init_set(&tmp, &ske->KEY);
+
+ klen = silc_mp_size(&tmp);
+
+ /* Format the KEY material into binary data */
+ tmpbuf = silc_calloc(klen, sizeof(unsigned char));
+ for (i = klen; i > 0; i--) {
+ tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
+ silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
+ }
+
+ buf = silc_buffer_alloc(1 + klen + hash_len);
+
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+ silc_buffer_format(buf,
+ SILC_STR_UI_CHAR(0),
+ SILC_STR_UI_XNSTRING(tmpbuf, klen),
+ SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
+ SILC_STR_END);
+
+ /* Take IVs */
+ memset(hash, 0, sizeof(hash));
+ buf->data[0] = 0;
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
+ memcpy(key->send_iv, hash, req_iv_len);
+ memset(hash, 0, sizeof(hash));
+ buf->data[0] = 1;
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
+ memcpy(key->receive_iv, hash, req_iv_len);
+ key->iv_len = req_iv_len;
+
+ /* Take the encryption keys. If requested key size is more than
+ the size of hash length we will distribute more key material
+ as protocol defines. */
+ buf->data[0] = 2;
+ if (enc_key_len > hash_len) {
+ SilcBuffer dist;
+ unsigned char k1[32], k2[32], k3[32];
+ unsigned char *dtmp;
+
+ /* XXX */
+ if (enc_key_len > (3 * hash_len))
+ return SILC_SKE_STATUS_ERROR;
+
+ memset(k1, 0, sizeof(k1));
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
+
+ /* XXX */
+ dist = silc_buffer_alloc(hash_len * 3);
+
+ silc_buffer_pull_tail(dist, klen + hash_len);
+ silc_buffer_format(dist,
+ SILC_STR_UI_XNSTRING(tmpbuf, klen),
+ SILC_STR_UI_XNSTRING(k1, hash_len),
+ SILC_STR_END);
+
+ memset(k2, 0, sizeof(k2));
+ silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
+
+ silc_buffer_pull(dist, klen + hash_len);
+ silc_buffer_format(dist,
+ SILC_STR_UI_XNSTRING(k2, hash_len),
+ SILC_STR_END);
+ silc_buffer_push(dist, klen + hash_len);
+
+ memset(k3, 0, sizeof(k3));
+ silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
+
+ dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
+ memcpy(dtmp, k1, hash_len);
+ memcpy(dtmp + hash_len, k2, hash_len);
+ memcpy(dtmp + hash_len, k3, hash_len);
+
+ key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ memcpy(key->send_enc_key, dtmp, enc_key_len);
+ key->enc_key_len = req_enc_key_len;
+
+ memset(dtmp, 0, (3 * hash_len));
+ memset(k1, 0, sizeof(k1));
+ memset(k2, 0, sizeof(k2));
+ memset(k3, 0, sizeof(k3));
+ silc_free(dtmp);
+ silc_buffer_free(dist);
+ } else {
+ /* Take normal hash as key */
+ memset(hash, 0, sizeof(hash));
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ memcpy(key->send_enc_key, hash, enc_key_len);
+ key->enc_key_len = req_enc_key_len;
+ }
+
+ buf->data[0] = 3;
+ if (enc_key_len > hash_len) {
+ SilcBuffer dist;
+ unsigned char k1[32], k2[32], k3[32];
+ unsigned char *dtmp;
+
+ /* XXX */
+ if (enc_key_len > (3 * hash_len))
+ return SILC_SKE_STATUS_ERROR;
+
+ memset(k1, 0, sizeof(k1));
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
+
+ /* XXX */
+ dist = silc_buffer_alloc(hash_len * 3);
+
+ silc_buffer_pull_tail(dist, klen + hash_len);
+ silc_buffer_format(dist,
+ SILC_STR_UI_XNSTRING(tmpbuf, klen),
+ SILC_STR_UI_XNSTRING(k1, hash_len),
+ SILC_STR_END);
+
+ memset(k2, 0, sizeof(k2));
+ silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
+
+ silc_buffer_pull(dist, klen + hash_len);
+ silc_buffer_format(dist,
+ SILC_STR_UI_XNSTRING(k2, hash_len),
+ SILC_STR_END);
+ silc_buffer_push(dist, klen + hash_len);
+
+ memset(k3, 0, sizeof(k3));
+ silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
+
+ dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
+ memcpy(dtmp, k1, hash_len);
+ memcpy(dtmp + hash_len, k2, hash_len);
+ memcpy(dtmp + hash_len, k3, hash_len);
+
+ key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ memcpy(key->receive_enc_key, dtmp, enc_key_len);
+ key->enc_key_len = req_enc_key_len;
+
+ memset(dtmp, 0, (3 * hash_len));
+ memset(k1, 0, sizeof(k1));
+ memset(k2, 0, sizeof(k2));
+ memset(k3, 0, sizeof(k3));
+ silc_free(dtmp);
+ silc_buffer_free(dist);
+ } else {
+ /* Take normal hash as key */
+ memset(hash, 0, sizeof(hash));
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ memcpy(key->receive_enc_key, hash, enc_key_len);
+ key->enc_key_len = req_enc_key_len;
+ }
+
+ /* Take HMAC key */
+ memset(hash, 0, sizeof(hash));
+ buf->data[0] = 4;
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
+ memcpy(key->hmac_key, hash, req_hmac_key_len);
+ key->hmac_key_len = req_hmac_key_len;
+
+ memset(tmpbuf, 0, klen);
+ silc_free(tmpbuf);
+
+ return SILC_SKE_STATUS_OK;
+}
--- /dev/null
+/*
+
+ silcske.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSKE_H
+#define SILCSKE_H
+
+#include "silcske_status.h"
+
+/* Forward declaration for SKE object. */
+typedef struct SilcSKEStruct *SilcSKE;
+
+/* Forward declaration for security properties. */
+typedef struct SilcSKESecurityPropertiesStruct *SilcSKESecurityProperties;
+
+/* Packet sending callback. Caller of the SKE routines must provide
+ a routine to send packets to negotiation parties. */
+typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet,
+ SilcPacketType type, void *context);
+
+/* Generic SKE callback function. This is called in various SKE
+ routines. The SilcSKE object sent as argument provides all the data
+ callers routine might need (payloads etc). */
+typedef void (*SilcSKECb)(SilcSKE ske, void *context);
+
+/* Supported Public Key Types, defined by the protocol */
+typedef enum {
+ SILC_SKE_PK_TYPE_SILC = 1, /* Mandatory type */
+ /* Optional types. These are not implemented currently
+ SILC_SKE_PK_TYPE_SSH2 = 2,
+ SILC_SKE_PK_TYPE_X509V3 = 3,
+ SILC_SKE_PK_TYPE_OPENPGP = 4,
+ SILC_SKE_PK_TYPE_SPKI = 5
+ */
+} SilcSKEPKType;
+
+/* Context passed to key material processing function. The function
+ returns the processed key material into this structure. */
+typedef struct {
+ unsigned char *send_iv;
+ unsigned char *receive_iv;
+ unsigned int iv_len;
+ unsigned char *send_enc_key;
+ unsigned char *receive_enc_key;
+ unsigned int enc_key_len;
+ unsigned char *hmac_key;
+ unsigned int hmac_key_len;
+} SilcSKEKeyMaterial;
+
+#define SILC_SKE_COOKIE_LEN 16
+
+#include "groups.h"
+#include "payload.h"
+
+/* Security Property Flags. */
+typedef enum {
+ SILC_SKE_SP_FLAG_NONE = (1L << 0),
+ SILC_SKE_SP_FLAG_NO_REPLY = (1L << 1),
+ SILC_SKE_SP_FLAG_PFS = (1L << 2),
+} SilcSKESecurityPropertyFlag;
+
+/* Security Properties negotiated between key exchange parties. This
+ structure is filled from the Key Exchange Start Payload which is used
+ to negotiate what security properties should be used in the
+ communication. */
+struct SilcSKESecurityPropertiesStruct {
+ unsigned char flags;
+ SilcSKEDiffieHellmanGroup group;
+ SilcPKCS pkcs;
+ SilcCipher cipher;
+ SilcHash hash;
+ /* XXX SilcCompression comp; */
+};
+
+struct SilcSKEStruct {
+ /* The connection object. This is initialized by the caller. */
+ SilcSocketConnection sock;
+
+ /* Security properties negotiated */
+ SilcSKESecurityProperties prop;
+
+ /* Key Exchange payloads filled during key negotiation with
+ remote data. Responder may save local data here as well. */
+ SilcSKEStartPayload *start_payload;
+ SilcSKEOnePayload *ke1_payload;
+ SilcSKETwoPayload *ke2_payload;
+
+ /* Temporary copy of the KE Start Payload used in the
+ HASH computation. */
+ SilcBuffer start_payload_copy;
+
+ /* If initiator, this is responders public key. If responder this
+ is our own public key. */
+ unsigned char *pk;
+ unsigned int pk_len;
+
+ /* Random number x, 1 < x < q. This is the secret exponent
+ used in Diffie Hellman computations. */
+ SilcInt x;
+
+ /* The secret shared key */
+ SilcInt KEY;
+
+ /* The hash value HASH of the key exchange */
+ unsigned char *hash;
+ unsigned int hash_len;
+
+ /* Random Number Generator. This is set by the caller and must
+ be free'd by the caller. */
+ SilcRng rng;
+
+ /* Pointer to the what ever user data. This is set by the caller
+ and is not touched by the SKE. The caller must also free this one. */
+ void *user_data;
+};
+
+/* Prototypes */
+SilcSKE silc_ske_alloc();
+void silc_ske_free(SilcSKE ske);
+SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ SilcSKEStartPayload *start_payload,
+ SilcSKESendPacketCb send_packet,
+ void *context);
+SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
+ SilcBuffer start_payload,
+ SilcSKECb callback,
+ void *context);
+SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+ SilcSKESendPacketCb send_packet,
+ void *context);
+SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+ SilcBuffer ke2_payload,
+ SilcSKECb callback,
+ void *context);
+SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ SilcBuffer start_payload,
+ SilcSKECb callback,
+ void *context);
+SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
+ SilcSKEStartPayload *start_payload,
+ SilcSKESendPacketCb send_packet,
+ void *context);
+SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
+ SilcBuffer ke1_payload,
+ SilcSKECb callback,
+ void *context);
+SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
+ unsigned char *pk,
+ unsigned int pk_len,
+ unsigned char *prv,
+ unsigned int prv_len,
+ SilcSKEPKType pk_type,
+ SilcSKESendPacketCb send_packet,
+ void *context);
+SilcSKEStatus silc_ske_end(SilcSKE ske,
+ SilcSKESendPacketCb send_packet,
+ void *context);
+SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
+ SilcSKESendPacketCb send_packet,
+ void *context);
+SilcSKEStatus
+silc_ske_assemble_security_properties(SilcSKE ske,
+ SilcSKEStartPayload **return_payload);
+SilcSKEStatus
+silc_ske_select_security_properties(SilcSKE ske,
+ SilcSKEStartPayload *payload,
+ SilcSKEStartPayload *remote_payload);
+SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
+ unsigned int len,
+ SilcInt *rnd);
+SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske,
+ unsigned char *pubkey,
+ unsigned int pubkey_len);
+SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
+ unsigned char *return_hash,
+ unsigned int *return_hash_len);
+SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
+ unsigned int req_iv_len,
+ unsigned int req_enc_key_len,
+ unsigned int req_hmac_key_len,
+ SilcSKEKeyMaterial *key);
+#endif
--- /dev/null
+/*
+
+ silcske_status.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2000 Pekka Riikonen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSKE_STATUS_H
+#define SILCSKE_STATUS_H
+
+/* Status flags returned by all SKE routines */
+typedef enum {
+ /* These are defined by the protocol */
+ SILC_SKE_STATUS_OK = 0,
+ SILC_SKE_STATUS_ERROR = 1,
+ SILC_SKE_STATUS_BAD_PAYLOAD = 2,
+ SILC_SKE_STATUS_UNKNOWN_GROUP = 3,
+ SILC_SKE_STATUS_UNKNOWN_CIPHER = 4,
+ SILC_SKE_STATUS_UNKNOWN_PKCS = 5,
+ SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION = 6,
+ SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY = 7,
+ SILC_SKE_STATUS_INCORRECT_SIGNATURE = 8,
+
+ SILC_SKE_STATUS_KEY_EXCHANGE_NOT_ACTIVE,
+ SILC_SKE_STATUS_BAD_RESERVED_FIELD,
+ SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH,
+ SILC_SKE_STATUS_INCORRECT_HASH,
+ SILC_SKE_STATUS_INCORRECT_PUBLIC_KEY,
+} SilcSKEStatus;
+
+#endif
--- /dev/null
+
+ ChangeLog file for zlib
+
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+ occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+ (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean" (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+ . zutil.c, zutil.h: added "const" for zmem*
+ . Make_vms.com: fixed some typos
+ . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+ . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+ . msdos/Makefile.*: use model-dependent name for the built zlib library
+ . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+ new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+ See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+ completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+ (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+ compression ratio on some files. This also allows inlining _tr_tally for
+ matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+ on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+ the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+ them at run time (thanks to Ken Raeburn for this suggestion). To create
+ trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+ gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occuring only with compression level 0 (thanks to
+ Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+ (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+ (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+ inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+ contrib/asm386/ by Gilles Vollant <info@winimage.com>
+ 386 asm code replacing longest_match().
+ contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+ A C++ I/O streams interface to the zlib gz* functions
+ contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
+ Another C++ I/O streams interface
+ contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ A very simple tar.gz file extractor using zlib
+ contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+ How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+ level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+ (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+ bit, so the decompressor could decompress all the correct data but went
+ on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+ small and medium models; this makes the library incompatible with previous
+ versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+ avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+ Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+ and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+ -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+ warning C4746: 'inflate_mask' : unsized array treated as '__far'
+ (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+ not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+ (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+ typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+ was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+ pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+ is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+ (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+ TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+ (one's complement) is now done inside crc32(). WARNING: this is
+ incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+ not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+ Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+ if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+ user-provided history buffer. This is supported only in deflateInit2
+ and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
--- /dev/null
+
+ Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page
+http://www.cdrom.com/pub/infozip/zlib/ which may have more recent information.
+
+
+1) I need a Windows DLL
+2) I need a Visual Basic interface to zlib
+3) compress() returns Z_BUF_ERROR
+4) deflate or inflate returns Z_BUF_ERROR
+5) Where is the zlib documentation (man pages, etc...)?
+6) Why don't you use GNU autoconf, libtool, etc...?
+7) There is a bug in zlib.
+8) I get "undefined reference to gzputc"
+
+
+
+1) I need a Windows DLL
+
+ The zlib sources can be compiled without change to produce a DLL.
+ If you want a precompiled DLL, see http://www.winimage.com/zLibDll
+
+
+2) I need a Visual Basic interface to zlib
+
+ See http://www.tcfb.com/dowseware/cmp-z-it.zip
+ http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm
+ and contrib/visual-basic.txt
+
+3) compress() returns Z_BUF_ERROR
+
+ Make sure that before the call of compress, the length of the
+ compressed buffer is equal to the total size of the compressed buffer
+ and not zero. For Visual Basic, check that this parameter is passed
+ by reference ("as any"), not by value ("as long").
+
+
+4) deflate or inflate returns Z_BUF_ERROR
+
+ Make sure that before the call avail_in and avail_out are not zero.
+
+
+5) Where is the zlib documentation (man pages, etc...)?
+
+ It's in zlib.h for the moment. Volunteers to transform this
+ to man pages, please contact jloup@gzip.org. Examples of zlib usage
+ are in the files example.c and minigzip.c.
+
+
+6) Why don't you use GNU autoconf, libtool, etc...?
+
+ Because we would like to keep zlib as a very small and simple package.
+ zlib is rather portable and doesn't need much configuration.
+
+
+7) There is a bug in zlib.
+
+ Most of the time, such problems are due to an incorrect usage
+ of zlib. Please try to reproduce the problem with a small
+ program and send us the corresponding source at zlib@quest.jpl.nasa.gov
+ Do not send multi-megabyte data files without prior agreement.
+
+
+8) I get "undefined reference to gzputc"
+
+ If "make test" produces something like
+ example.o(.text+0x174):
+ check that you don't have old files libz.* in /usr/lib, /usr/local/lib
+ or /usr/X11R6/lib. Remove old versions then do "make install".
+
--- /dev/null
+ChangeLog history of changes
+INDEX this file
+FAQ Frequently Asked Questions about zlib
+Make_vms.com script for Vax/VMS
+Makefile makefile for Unix (generated by configure)
+Makefile.in makefile for Unix (template for configure)
+Makefile.riscos makefile for RISCOS
+README guess what
+algorithm.txt description of the (de)compression algorithm
+configure configure script for Unix
+descrip.mms makefile for Vax/VMS
+zlib.3 mini man page for zlib (volunteers to write full
+ man pages from zlib.h welcome. write to jloup@gzip.org)
+
+amiga/Makefile.sas makefile for Amiga SAS/C
+amiga/Makefile.pup makefile for Amiga powerUP SAS/C PPC
+
+msdos/Makefile.w32 makefile for Microsoft Visual C++ 32-bit
+msdos/Makefile.b32 makefile for Borland C++ 32-bit
+msdos/Makefile.bor makefile for Borland C/C++ 16-bit
+msdos/Makefile.dj2 makefile for DJGPP 2.x
+msdos/Makefile.emx makefile for EMX 0.9c (32-bit DOS/OS2)
+msdos/Makefile.msc makefile for Microsoft C 16-bit
+msdos/Makefile.tc makefile for Turbo C
+msdos/Makefile.wat makefile for Watcom C
+msdos/zlib.def definition file for Windows DLL
+msdos/zlib.rc definition file for Windows DLL
+
+nt/Makefile.nt makefile for Windows NT
+nt/zlib.dnt definition file for Windows NT DLL
+nt/Makefile.emx makefile for EMX 0.9c/RSXNT 1.41 (Win32 Intel)
+nt/Makefile.gcc makefile for Windows NT using GCC (mingw32)
+
+
+ zlib public header files (must be kept):
+zconf.h
+zlib.h
+
+ private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+deflate.c
+deflate.h
+gzio.c
+infblock.c
+infblock.h
+infcodes.c
+infcodes.h
+inffast.c
+inffast.h
+inflate.c
+inftrees.c
+inftrees.h
+infutil.c
+infutil.h
+maketree.c
+trees.c
+uncompr.c
+zutil.c
+zutil.h
+
+ source files for sample programs:
+example.c
+minigzip.c
+
+ unsupported contribution by third parties
+
+contrib/asm386/ by Gilles Vollant <info@winimage.com>
+ 386 asm code replacing longest_match().
+
+contrib/minizip/ by Gilles Vollant <info@winimage.com>
+ Mini zip and unzip based on zlib
+ See http://www.winimage.com/zLibDll/unzip.html
+
+contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+ A C++ I/O streams interface to the zlib gz* functions
+
+contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
+ Another C++ I/O streams interface
+
+contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ A very simple tar.gz extractor using zlib
+
+contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+ How to use compress(), uncompress() and the gz* functions from VB.
--- /dev/null
+$! make libz under VMS
+$! written by Martin P.J. Zinser <m.zinser@gsi.de>
+$!
+$! Look for the compiler used
+$!
+$ ccopt = ""
+$ if f$getsyi("HW_MODEL").ge.1024
+$ then
+$ ccopt = "/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs.""
+$ then
+$ comp = "__vaxc__=1"
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include:
+$ ccopt = "/decc/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ endif
+$ endif
+$!
+$! Build the thing plain or with mms
+$!
+$ write sys$output "Compiling Zlib sources ..."
+$ if f$search("SYS$SYSTEM:MMS.EXE").eqs.""
+$ then
+$ dele example.obj;*,minigzip.obj;*
+$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" -
+ adler32.c zlib.h zconf.h
+$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" -
+ compress.c zlib.h zconf.h
+$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" -
+ crc32.c zlib.h zconf.h
+$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" -
+ deflate.c deflate.h zutil.h zlib.h zconf.h
+$ CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" -
+ gzio.c zutil.h zlib.h zconf.h
+$ CALL MAKE infblock.OBJ "CC ''CCOPT' infblock" -
+ infblock.c zutil.h zlib.h zconf.h infblock.h
+$ CALL MAKE infcodes.OBJ "CC ''CCOPT' infcodes" -
+ infcodes.c zutil.h zlib.h zconf.h inftrees.h
+$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" -
+ inffast.c zutil.h zlib.h zconf.h inffast.h
+$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" -
+ inflate.c zutil.h zlib.h zconf.h infblock.h
+$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" -
+ inftrees.c zutil.h zlib.h zconf.h inftrees.h
+$ CALL MAKE infutil.OBJ "CC ''CCOPT' infutil" -
+ infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" -
+ trees.c deflate.h zutil.h zlib.h zconf.h
+$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" -
+ uncompr.c zlib.h zconf.h
+$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" -
+ zutil.c zutil.h zlib.h zconf.h
+$ write sys$output "Building Zlib ..."
+$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ
+$ write sys$output "Building example..."
+$ CALL MAKE example.OBJ "CC ''CCOPT' example" -
+ example.c zlib.h zconf.h
+$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb
+$ write sys$output "Building minigzip..."
+$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" -
+ minigzip.c zlib.h zconf.h
+$ call make minigzip.exe -
+ "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" -
+ minigzip.obj libz.olb
+$ else
+$ mms/macro=('comp')
+$ endif
+$ write sys$output "Zlib build completed"
+$ exit
+$!
+$!
+$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8 What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$ Argument = P'arg
+$ If Argument .Eqs. "" Then Goto Exit
+$ El=0
+$Loop2:
+$ File = F$Element(El," ",Argument)
+$ If File .Eqs. " " Then Goto Endl
+$ AFile = ""
+$Loop3:
+$ OFile = AFile
+$ AFile = F$Search(File)
+$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$ Goto Loop3
+$NextEL:
+$ El = El + 1
+$ Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
--- /dev/null
+# Makefile for zlib
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=gcc
+
+CFLAGS=-fPIC -O3 -DHAVE_UNISTD_H -DUSE_MMAP
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=-L. -lz
+LDSHARED=gcc -shared -Wl,-soname,libz.so.1
+CPP=gcc -E
+
+VER=1.1.3
+LIBS=libz.so.1.1.3
+SHAREDLIB=libz.so
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+SHELL=/bin/sh
+
+prefix =/usr/local
+exec_prefix =--cache-file=../.././config.cache
+libdir =${exec_prefix}/lib
+includedir =${prefix}/include
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README FAQ INDEX ChangeLog configure Make*[a-z0-9] *.[ch] *.mms \
+ algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+ nt/Make*[a-z0-9] nt/zlib.dnt amiga/Make*.??? os2/M*.os2 os2/zlib.def \
+ contrib/RE*.contrib contrib/*.txt contrib/asm386/*.asm contrib/asm386/*.c \
+ contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/asm[56]86/*.?86 \
+ contrib/asm[56]86/*.S contrib/iostream/*.cpp \
+ contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \
+ contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 \
+ contrib/minizip/[CM]*[pe] contrib/minizip/*.[ch] contrib/minizip/*.[td]?? \
+ contrib/delphi*/*.???
+
+all: example minigzip
+
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+libz.a: $(OBJS) $(OBJA)
+ $(AR) $@ $(OBJS) $(OBJA)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+$(SHAREDLIB).$(VER): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f $(SHAREDLIB) $(SHAREDLIB).1
+ ln -s $@ $(SHAREDLIB)
+ ln -s $@ $(SHAREDLIB).1
+
+example: example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+ -@if [ ! -d $(includedir) ]; then mkdir $(includedir); fi
+ -@if [ ! -d $(libdir) ]; then mkdir $(libdir); fi
+ cp zlib.h zconf.h $(includedir)
+ chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+ cp $(LIBS) $(libdir)
+ cd $(libdir); chmod 755 $(LIBS)
+ -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+ cd $(libdir); if test -f $(SHAREDLIB).$(VER); then \
+ rm -f $(SHAREDLIB) $(SHAREDLIB).1; \
+ ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB); \
+ ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB).1; \
+ (ldconfig || true) >/dev/null 2>&1; \
+ fi
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+uninstall:
+ cd $(includedir); \
+ v=$(VER); \
+ if test -f zlib.h; then \
+ v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`; \
+ rm -f zlib.h zconf.h; \
+ fi; \
+ cd $(libdir); rm -f libz.a; \
+ if test -f $(SHAREDLIB).$$v; then \
+ rm -f $(SHAREDLIB).$$v $(SHAREDLIB) $(SHAREDLIB).1; \
+ fi
+
+clean:
+ rm -f *.o *~ example minigzip libz.a libz.so* foo.gz so_locations \
+ _match.s maketree
+
+distclean: clean
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c contrib/minizip/test.zip
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c contrib/minizip/test.zip
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
--- /dev/null
+# Makefile for zlib
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=-L. -lz
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+VER=1.1.3
+LIBS=libz.a
+SHAREDLIB=libz.so
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+SHELL=/bin/sh
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+libdir = ${exec_prefix}/lib
+includedir = ${prefix}/include
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README FAQ INDEX ChangeLog configure Make*[a-z0-9] *.[ch] *.mms \
+ algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+ nt/Make*[a-z0-9] nt/zlib.dnt amiga/Make*.??? os2/M*.os2 os2/zlib.def \
+ contrib/RE*.contrib contrib/*.txt contrib/asm386/*.asm contrib/asm386/*.c \
+ contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/asm[56]86/*.?86 \
+ contrib/asm[56]86/*.S contrib/iostream/*.cpp \
+ contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \
+ contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 \
+ contrib/minizip/[CM]*[pe] contrib/minizip/*.[ch] contrib/minizip/*.[td]?? \
+ contrib/delphi*/*.???
+
+all: example minigzip
+
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+libz.a: $(OBJS) $(OBJA)
+ $(AR) $@ $(OBJS) $(OBJA)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+$(SHAREDLIB).$(VER): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f $(SHAREDLIB) $(SHAREDLIB).1
+ ln -s $@ $(SHAREDLIB)
+ ln -s $@ $(SHAREDLIB).1
+
+example: example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+ -@if [ ! -d $(includedir) ]; then mkdir $(includedir); fi
+ -@if [ ! -d $(libdir) ]; then mkdir $(libdir); fi
+ cp zlib.h zconf.h $(includedir)
+ chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+ cp $(LIBS) $(libdir)
+ cd $(libdir); chmod 755 $(LIBS)
+ -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+ cd $(libdir); if test -f $(SHAREDLIB).$(VER); then \
+ rm -f $(SHAREDLIB) $(SHAREDLIB).1; \
+ ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB); \
+ ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB).1; \
+ (ldconfig || true) >/dev/null 2>&1; \
+ fi
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+uninstall:
+ cd $(includedir); \
+ v=$(VER); \
+ if test -f zlib.h; then \
+ v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`; \
+ rm -f zlib.h zconf.h; \
+ fi; \
+ cd $(libdir); rm -f libz.a; \
+ if test -f $(SHAREDLIB).$$v; then \
+ rm -f $(SHAREDLIB).$$v $(SHAREDLIB) $(SHAREDLIB).1; \
+ fi
+
+clean:
+ rm -f *.o *~ example minigzip libz.a libz.so* foo.gz so_locations \
+ _match.s maketree
+
+distclean: clean
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c contrib/minizip/test.zip
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c contrib/minizip/test.zip
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
--- /dev/null
+# Project: zlib_1_03
+# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430
+# test works out-of-the-box, installs `somewhere' on demand
+
+# Toolflags:
+CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fah
+C++flags = -c -depend !Depend -IC: -throwback
+Linkflags = -aif -c++ -o $@
+ObjAsmflags = -throwback -NoCache -depend !Depend
+CMHGflags =
+LibFileflags = -c -l -o $@
+Squeezeflags = -o $@
+
+# change the line below to where _you_ want the library installed.
+libdest = lib:zlib
+
+# Final targets:
+@.lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \
+ @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \
+ @.o.uncompr @.o.zutil
+ LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \
+ @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \
+ @.o.trees @.o.uncompr @.o.zutil
+test: @.minigzip @.example @.lib
+ @copy @.lib @.libc A~C~DF~L~N~P~Q~RS~TV
+ @echo running tests: hang on.
+ @/@.minigzip -f -9 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -f -1 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -h -9 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -h -1 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -9 libc
+ @/@.minigzip -d libc-gz
+ @/@.minigzip -1 libc
+ @/@.minigzip -d libc-gz
+ @diff @.lib @.libc
+ @echo that should have reported '@.lib and @.libc identical' if you have diff.
+ @/@.example @.fred @.fred
+ @echo that will have given lots of hello!'s.
+
+@.minigzip: @.o.minigzip @.lib C:o.Stubs
+ Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs
+@.example: @.o.example @.lib C:o.Stubs
+ Link $(Linkflags) @.o.example @.lib C:o.Stubs
+
+install: @.lib
+ cdir $(libdest)
+ cdir $(libdest).h
+ @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV
+ @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV
+ @copy @.lib $(libdest).lib A~C~DF~L~N~P~Q~RS~TV
+ @echo okay, installed zlib in $(libdest)
+
+clean:; remove @.minigzip
+ remove @.example
+ remove @.libc
+ -wipe @.o.* F~r~cV
+ remove @.fred
+
+# User-editable dependencies:
+.c.o:
+ cc $(ccflags) -o $@ $<
+
+# Static dependencies:
+
+# Dynamic dependencies:
+o.example: c.example
+o.example: h.zlib
+o.example: h.zconf
+o.minigzip: c.minigzip
+o.minigzip: h.zlib
+o.minigzip: h.zconf
+o.adler32: c.adler32
+o.adler32: h.zlib
+o.adler32: h.zconf
+o.compress: c.compress
+o.compress: h.zlib
+o.compress: h.zconf
+o.crc32: c.crc32
+o.crc32: h.zlib
+o.crc32: h.zconf
+o.deflate: c.deflate
+o.deflate: h.deflate
+o.deflate: h.zutil
+o.deflate: h.zlib
+o.deflate: h.zconf
+o.gzio: c.gzio
+o.gzio: h.zutil
+o.gzio: h.zlib
+o.gzio: h.zconf
+o.infblock: c.infblock
+o.infblock: h.zutil
+o.infblock: h.zlib
+o.infblock: h.zconf
+o.infblock: h.infblock
+o.infblock: h.inftrees
+o.infblock: h.infcodes
+o.infblock: h.infutil
+o.infcodes: c.infcodes
+o.infcodes: h.zutil
+o.infcodes: h.zlib
+o.infcodes: h.zconf
+o.infcodes: h.inftrees
+o.infcodes: h.infblock
+o.infcodes: h.infcodes
+o.infcodes: h.infutil
+o.infcodes: h.inffast
+o.inffast: c.inffast
+o.inffast: h.zutil
+o.inffast: h.zlib
+o.inffast: h.zconf
+o.inffast: h.inftrees
+o.inffast: h.infblock
+o.inffast: h.infcodes
+o.inffast: h.infutil
+o.inffast: h.inffast
+o.inflate: c.inflate
+o.inflate: h.zutil
+o.inflate: h.zlib
+o.inflate: h.zconf
+o.inflate: h.infblock
+o.inftrees: c.inftrees
+o.inftrees: h.zutil
+o.inftrees: h.zlib
+o.inftrees: h.zconf
+o.inftrees: h.inftrees
+o.inftrees: h.inffixed
+o.infutil: c.infutil
+o.infutil: h.zutil
+o.infutil: h.zlib
+o.infutil: h.zconf
+o.infutil: h.infblock
+o.infutil: h.inftrees
+o.infutil: h.infcodes
+o.infutil: h.infutil
+o.trees: c.trees
+o.trees: h.deflate
+o.trees: h.zutil
+o.trees: h.zlib
+o.trees: h.zconf
+o.trees: h.trees
+o.uncompr: c.uncompr
+o.uncompr: h.zlib
+o.uncompr: h.zconf
+o.zutil: c.zutil
+o.zutil: h.zutil
+o.zutil: h.zlib
+o.zutil: h.zconf
--- /dev/null
+zlib 1.1.3 is a general purpose data compression library. All the code
+is thread safe. The data format used by the zlib library
+is described by RFCs (Request for Comments) 1950 to 1952 in the files
+ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+format) and rfc1952.txt (gzip format). These documents are also available in
+other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact jloup@gzip.org). A usage
+example of the library is given in the file example.c which also tests that
+the library is working correctly. Another example is given in the file
+minigzip.c. The compression library itself is composed of all source files
+except example.c and minigzip.c.
+
+To compile all files and run the test program, follow the instructions
+given at the top of Makefile. In short "make test; make install"
+should work for most machines. For Unix: "configure; make test; make install"
+For MSDOS, use one of the special makefiles such as Makefile.msc.
+For VMS, use Make_vms.com or descrip.mms.
+
+Questions about zlib should be sent to <zlib@quest.jpl.nasa.gov>, or to
+Gilles Vollant <info@winimage.com> for the Windows DLL version.
+The zlib home page is http://www.cdrom.com/pub/infozip/zlib/
+The official zlib ftp site is ftp://ftp.cdrom.com/pub/infozip/zlib/
+Before reporting a problem, please check those sites to verify that
+you have the latest version of zlib; otherwise get the latest version and
+check whether the problem still exists or not.
+
+Mark Nelson <markn@tiny.com> wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available in
+http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.1.3 are documented in the file ChangeLog.
+The main changes since 1.1.2 are:
+
+- fix "an inflate input buffer bug that shows up on rare but persistent
+ occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+ (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+plus many changes for portability.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit 1.1
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+See the zlib home page http://www.cdrom.com/pub/infozip/zlib/ for details.
+
+A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk>
+is in the CPAN (Comprehensive Perl Archive Network) sites, such as:
+ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib*
+
+A Python interface to zlib written by A.M. Kuchling <amk@magnet.com>
+is available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com>
+is availlable at http://www.westend.com/~kupries/doc/trf/man/man.html
+
+An experimental package to read and write files in .zip format,
+written on top of zlib by Gilles Vollant <info@winimage.com>, is
+available at http://www.winimage.com/zLibDll/unzip.html
+and also in the contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc
+ and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL
+ The zlib DLL support was initially done by Alessandro Iacopetti and is
+ now maintained by Gilles Vollant <info@winimage.com>. Check the zlib DLL
+ home page at http://www.winimage.com/zLibDll
+
+ From Visual Basic, you can call the DLL functions which do not take
+ a structure as argument: compress, uncompress and all gz* functions.
+ See contrib/visual-basic.txt for more information, or get
+ http://www.tcfb.com/dowseware/cmp-z-it.zip
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization.
+ With -O, one libpng test fails. The test works in 32 bit mode (with
+ the -n32 compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1
+ it works when compiled with cc.
+
+- on Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1
+ is necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works
+ with other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For Turbo C the small model is supported only with reduced performance to
+ avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+
+- For PalmOs, see http://www.cs.uit.no/~perm/PASTA/pilot/software.html
+ Per Harald Myrvang <perm@stud.cs.uit.no>
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate
+ and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib;
+ they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes.
--- /dev/null
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
--- /dev/null
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data. The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length). Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes. (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The real question is, given a Huffman tree, how to decode fast. The most
+important realization is that shorter codes are much more common than
+longer codes, so pay attention to decoding the short codes fast, and let
+the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code. It gets that many bits from the
+stream, and looks it up in the table. The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table. If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code. However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table. What inflate() does is
+simply to make the number of bits in the first table a variable, and set it
+for the maximum speed.
+
+inflate() sends new trees relatively often, so it is possibly set for a
+smaller first level table than an application that has only one tree for
+all the data. For inflate, which has 286 possible codes for the
+literal/length tree, the size of the first table is nine bits. Also the
+distance trees have 30 possible values, and the size of the first table is
+six bits. Note that for each of those cases, the table ended up one bit
+longer than the ``average'' code length, i.e. the code length of an
+approximately flat code which would be a little more than eight bits for
+286 symbols and a little less than five bits for 30 symbols. It would be
+interesting to see if optimizing the first level table for other
+applications gave values within a bit or two of the flat code size.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually
+looks like. You are correct that it's not a Huffman tree. It is simply a
+lookup table for the first, let's say, nine bits of a Huffman symbol. The
+symbol could be as short as one bit or as long as 15 bits. If a particular
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits. For example, if the
+symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points
+to another similar table for the remaining bits. Again, there are duplicated
+entries as needed. The idea is that most of the time the symbol will be short
+and there will only be one table look up. (That's whole idea behind data
+compression in the first place.) For the less frequent long symbols, there
+will be two lookups. If you had a compression method with really long
+symbols, you could have as many levels of lookups as is efficient. For
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in
+the above example are gobbled), or it contains the translation for the symbol
+and the number of bits to gobble. Then you start again with the next
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the
+longest symbol is? The reason is that if you do that, you end up spending
+more time filling in duplicate symbol entries than you do actually decoding.
+At least for deflate's output that generates new trees every several 10's of
+kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code
+would take too long if you're only decoding several thousand symbols. At the
+other extreme, you could make a new table for every bit in the code. In fact,
+that's essentially a Huffman tree. But then you spend two much time
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode to and how many bits that is, i.e. how
+many bits to gobble. Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to
+be constructed. That's compared to 64 entries for a single table. Or
+compared to 16 entries for a Huffman tree (six two entry tables and one four
+entry table). Assuming that the code ideally represents the probability of
+the symbols, it takes on the average 1.25 lookups per symbol. That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the
+Huffman tree.
+
+There, I think that gives you a picture of what's going on. For inflate, the
+meaning of a particular symbol is often more than just a letter. It can be a
+byte (a "literal"), or it can be either a length or a distance which
+indicates a base value and a number of bits to fetch after the code that is
+added to the base value. Or it might be the special end-of-block code. The
+data structures created in inftrees.c try to encode all that information
+compactly in the tables.
+
+
+Jean-loup Gailly Mark Adler
+jloup@gzip.org madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+ftp://ds.internic.net/rfc/rfc1951.txt
--- /dev/null
+# Amiga powerUP (TM) Makefile
+# makefile for libpng and SAS C V6.58/7.00 PPC compiler
+# Copyright (C) 1998 by Andreas R. Kleinert
+
+CC = scppc
+CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \
+ OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8
+LIBNAME = libzip.a
+AR = ppc-amigaos-ar
+AR_FLAGS = cr
+RANLIB = ppc-amigaos-ranlib
+LDFLAGS = -r -o
+LDLIBS = LIB:scppc.a
+LN = ppc-amigaos-ld
+RM = delete quiet
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example minigzip
+
+test: all
+ example
+ echo hello world | minigzip | minigzip -d
+
+$(LIBNAME): $(OBJS)
+ $(AR) $(AR_FLAGS) $@ $(OBJS)
+ $(RANLIB) $@
+
+example: example.o $(LIBNAME)
+ $(LN) $(LDFLAGS) example LIB:c_ppc.o example.o $(LIBNAME) $(LDLIBS) LIB:end.o
+
+minigzip: minigzip.o $(LIBNAME)
+ $(LN) $(LDFLAGS) minigzip LIB:c_ppc.o minigzip.o $(LIBNAME) $(LDLIBS) LIB:end.o
+
+clean:
+ $(RM) *.o example minigzip $(LIBNAME) foo.gz
+
+zip:
+ zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \
+ descrip.mms *.[ch]
+
+tgz:
+ cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \
+ zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zutil.h zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zutil.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.o: zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
--- /dev/null
+# SMakefile for zlib
+# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
+# Osma Ahvenlampi <Osma.Ahvenlampi@hut.fi>
+# Amiga, SAS/C 6.56 & Smake
+
+CC=sc
+CFLAGS=OPT
+#CFLAGS=OPT CPU=68030
+#CFLAGS=DEBUG=LINE
+LDFLAGS=LIB z.lib
+
+SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
+ NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: SCOPTIONS example minigzip
+
+test: all
+ `cd`/example
+ echo hello world | minigzip | minigzip -d
+
+install: z.lib
+ copy zlib.h zconf.h INCLUDE: clone
+ copy z.lib LIB: clone
+
+z.lib: $(OBJS)
+ oml z.lib r $(OBJS)
+
+example: example.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
+
+clean:
+ -delete force quiet *.o example minigzip z.lib foo.gz *.lnk SCOPTIONS
+
+SCOPTIONS: Smakefile
+ copy to $@ <from <
+$(SCOPTIONS)
+<
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zutil.h zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zutil.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.o: zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
--- /dev/null
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
--- /dev/null
+#!/bin/sh
+# configure script for zlib. This script is needed only if
+# you wish to build a shared library and your system supports them,
+# of if you need special compiler, flags or install directory.
+# Otherwise, you can just use directly "make test; make install"
+#
+# To create a shared library, use "configure --shared"; by default a static
+# library is created. If the primitive shared library support provided here
+# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz
+#
+# To impose specific compiler or flags or install directory, use for example:
+# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+# LDSHARED is the command to be used to create a shared library
+
+# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
+# If you have problems, try without defining CC and CFLAGS before reporting
+# an error.
+
+LIBS=libz.a
+SHAREDLIB=libz.so
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
+AR=${AR-"ar rc"}
+RANLIB=${RANLIB-"ranlib"}
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-'${prefix}'}
+libdir=${libdir-'${exec_prefix}/lib'}
+includedir=${includedir-'${prefix}/include'}
+shared_ext='.so'
+shared=0
+gcc=0
+old_cc="$CC"
+old_cflags="$CFLAGS"
+
+while test $# -ge 1
+do
+case "$1" in
+ -h* | --h*)
+ echo 'usage:'
+ echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]'
+ echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]'
+ exit 0;;
+ -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;;
+ -p* | --p*) prefix="$2"; shift; shift;;
+ -e* | --e*) exec_prefix="$2"; shift; shift;;
+ -l* | --l*) libdir="$2"; shift; shift;;
+ -i* | --i*) includedir="$2"; shift; shift;;
+ -s* | --s*) shared=1; shift;;
+ esac
+done
+
+test=ztest$$
+cat > $test.c <<EOF
+extern int getchar();
+int hello() {return getchar();}
+EOF
+
+test -z "$CC" && echo Checking for gcc...
+cc=${CC-gcc}
+cflags=${CFLAGS-"-O3"}
+# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
+case "$cc" in
+ *gcc*) gcc=1;;
+esac
+
+if test "$gcc" -eq 1 && ($cc -c $cflags $test.c) 2>/dev/null; then
+ CC="$cc"
+ SFLAGS=${CFLAGS-"-fPIC -O3"}
+ CFLAGS="$cflags"
+ case `(uname -s || echo unknown) 2>/dev/null` in
+ Linux | linux) LDSHARED=${LDSHARED-"gcc -shared -Wl,-soname,libz.so.1"};;
+ *) LDSHARED=${LDSHARED-"gcc -shared"};;
+ esac
+else
+ # find system name and corresponding cc options
+ CC=${CC-cc}
+ case `(uname -sr || echo unknown) 2>/dev/null` in
+ HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
+ CFLAGS=${CFLAGS-"-O"}
+# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
+ LDSHARED=${LDSHARED-"ld -b"}
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl';;
+ IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+ CFLAGS=${CFLAGS-"-ansi -O2"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,$SHAREDLIB -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};;
+ OSF1*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ QNX*) SFLAGS=${CFLAGS-"-4 -O"}
+ CFLAGS=${CFLAGS-"-4 -O"}
+ LDSHARED=${LDSHARED-"cc"}
+ RANLIB=${RANLIB-"true"}
+ AR="cc -A";;
+ SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+ CFLAGS=${CFLAGS-"-O3"}
+ LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};;
+ SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."}
+ CFLAGS=${CFLAGS-"-fast -xcg89"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+ CFLAGS=${CFLAGS-"-O2"}
+ LDSHARED=${LDSHARED-"ld"};;
+ UNIX_System_V\ 4.2.0)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ UNIX_SV\ 4.2MP)
+ SFLAGS=${CFLAGS-"-Kconform_pic -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ # send working options for other systems to support@gzip.org
+ *) SFLAGS=${CFLAGS-"-O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ esac
+fi
+
+if test $shared -eq 1; then
+ echo Checking for shared library support...
+ # we must test in two steps (cc then ld), required at least on SunOS 4.x
+ if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" &&
+ test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then
+ CFLAGS="$SFLAGS"
+ LIBS="$SHAREDLIB.$VER"
+ echo Building shared library $SHAREDLIB.$VER with $CC.
+ elif test -z "$old_cc" -a -z "$old_cflags"; then
+ echo No shared library suppport.
+ shared=0;
+ else
+ echo 'No shared library suppport; try without defining CC and CFLAGS'
+ shared=0;
+ fi
+fi
+if test $shared -eq 0; then
+ LDSHARED="$CC"
+ echo Building static library $LIBS version $VER with $CC.
+fi
+
+cat > $test.c <<EOF
+#include <unistd.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ CFLAGS="$CFLAGS -DHAVE_UNISTD_H"
+ echo "Checking for unistd.h... Yes."
+else
+ echo "Checking for unistd.h... No."
+fi
+
+cat > $test.c <<EOF
+#include <errno.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for errno.h... Yes."
+else
+ echo "Checking for errno.h... No."
+ CFLAGS="$CFLAGS -DNO_ERRNO_H"
+fi
+
+cat > $test.c <<EOF
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+caddr_t hello() {
+ return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0);
+}
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ CFLAGS="$CFLAGS -DUSE_MMAP"
+ echo Checking for mmap support... Yes.
+else
+ echo Checking for mmap support... No.
+fi
+
+CPP=${CPP-"$CC -E"}
+case $CFLAGS in
+ *ASMV*)
+ if test "`nm $test.o | grep _hello`" = ""; then
+ CPP="$CPP -DNO_UNDERLINE"
+ echo Checking for underline in external names... No.
+ else
+ echo Checking for underline in external names... Yes.
+ fi;;
+esac
+
+rm -f $test.[co] $test$shared_ext
+
+# udpate Makefile
+sed < Makefile.in "
+/^CC *=/s%=.*%=$CC%
+/^CFLAGS *=/s%=.*%=$CFLAGS%
+/^CPP *=/s%=.*%=$CPP%
+/^LDSHARED *=/s%=.*%=$LDSHARED%
+/^LIBS *=/s%=.*%=$LIBS%
+/^SHAREDLIB *=/s%=.*%=$SHAREDLIB%
+/^AR *=/s%=.*%=$AR%
+/^RANLIB *=/s%=.*%=$RANLIB%
+/^VER *=/s%=.*%=$VER%
+/^prefix *=/s%=.*%=$prefix%
+/^exec_prefix *=/s%=.*%=$exec_prefix%
+/^libdir *=/s%=.*%=$libdir%
+/^includedir *=/s%=.*%=$includedir%
+" > Makefile
--- /dev/null
+All files under this contrib directory are UNSUPPORTED. There were
+provided by users of zlib and were not tested by the authors of zlib.
+Use at your own risk. Please contact the authors of the contributions
+for help about these, not the zlib authors. Thanks.
+
+
+asm386/ by Gilles Vollant <info@winimage.com>
+ 386 asm code replacing longest_match(), for Visual C++ 4.2 and ML 6.11c
+
+asm586/ and asm686/ by Brian Raiter <breadbox@muppetlabs.com>
+ asm code for Pentium and Pentium Pro
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+delphi/ by Bob Dellaca <bobdl@xtra.co.nz>
+ Support for Delphi
+
+delphi2/ by Davide Moretti <dave@rimini.com>
+ Another support for C++Builder and Delphi
+
+minizip/ by Gilles Vollant <info@winimage.com>
+ Mini zip and unzip based on zlib
+ See http://www.winimage.com/zLibDll/unzip.html
+
+iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+ A C++ I/O streams interface to the zlib gz* functions
+
+iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
+ Another C++ I/O streams interface
+
+untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ A very simple tar.gz file extractor using zlib
+
+visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+ How to use compress(), uncompress() and the gz* functions from VB.
--- /dev/null
+;
+; gvmat32.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant.
+; File written by Gilles Vollant, by modifiying the longest_match
+; from Jean-loup Gailly in deflate.c
+; It need wmask == 0x7fff
+; (assembly code is faster with a fixed wmask)
+;
+; For Visual C++ 4.2 and ML 6.11c (version in directory \MASM611C of Win95 DDK)
+; I compile with : "ml /coff /Zi /c gvmat32.asm"
+;
+
+;uInt longest_match_7fff(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; /* current match */
+
+ NbStack equ 76
+ cur_match equ dword ptr[esp+NbStack-0]
+ str_s equ dword ptr[esp+NbStack-4]
+; 5 dword on top (ret,ebp,esi,edi,ebx)
+ adrret equ dword ptr[esp+NbStack-8]
+ pushebp equ dword ptr[esp+NbStack-12]
+ pushedi equ dword ptr[esp+NbStack-16]
+ pushesi equ dword ptr[esp+NbStack-20]
+ pushebx equ dword ptr[esp+NbStack-24]
+
+ chain_length equ dword ptr [esp+NbStack-28]
+ limit equ dword ptr [esp+NbStack-32]
+ best_len equ dword ptr [esp+NbStack-36]
+ window equ dword ptr [esp+NbStack-40]
+ prev equ dword ptr [esp+NbStack-44]
+ scan_start equ word ptr [esp+NbStack-48]
+ wmask equ dword ptr [esp+NbStack-52]
+ match_start_ptr equ dword ptr [esp+NbStack-56]
+ nice_match equ dword ptr [esp+NbStack-60]
+ scan equ dword ptr [esp+NbStack-64]
+
+ windowlen equ dword ptr [esp+NbStack-68]
+ match_start equ dword ptr [esp+NbStack-72]
+ strend equ dword ptr [esp+NbStack-76]
+ NbStackAdd equ (NbStack-24)
+
+ .386p
+
+ name gvmatch
+ .MODEL FLAT
+
+
+
+; all the +4 offsets are due to the addition of pending_buf_size (in zlib
+; in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, remove the +4).
+; Note : these value are good with a 8 bytes boundary pack structure
+ dep_chain_length equ 70h+4
+ dep_window equ 2ch+4
+ dep_strstart equ 60h+4
+ dep_prev_length equ 6ch+4
+ dep_nice_match equ 84h+4
+ dep_w_size equ 20h+4
+ dep_prev equ 34h+4
+ dep_w_mask equ 28h+4
+ dep_good_match equ 80h+4
+ dep_match_start equ 64h+4
+ dep_lookahead equ 68h+4
+
+
+_TEXT segment
+
+IFDEF NOUNDERLINE
+ public longest_match_7fff
+; public match_init
+ELSE
+ public _longest_match_7fff
+; public _match_init
+ENDIF
+
+ MAX_MATCH equ 258
+ MIN_MATCH equ 3
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+
+
+
+IFDEF NOUNDERLINE
+;match_init proc near
+; ret
+;match_init endp
+ELSE
+;_match_init proc near
+; ret
+;_match_init endp
+ENDIF
+
+
+IFDEF NOUNDERLINE
+longest_match_7fff proc near
+ELSE
+_longest_match_7fff proc near
+ENDIF
+
+ mov edx,[esp+4]
+
+
+
+ push ebp
+ push edi
+ push esi
+ push ebx
+
+ sub esp,NbStackAdd
+
+; initialize or check the variables used in match.asm.
+ mov ebp,edx
+
+; chain_length = s->max_chain_length
+; if (prev_length>=good_match) chain_length >>= 2
+ mov edx,[ebp+dep_chain_length]
+ mov ebx,[ebp+dep_prev_length]
+ cmp [ebp+dep_good_match],ebx
+ ja noshr
+ shr edx,2
+noshr:
+; we increment chain_length because in the asm, the --chain_lenght is in the beginning of the loop
+ inc edx
+ mov edi,[ebp+dep_nice_match]
+ mov chain_length,edx
+ mov eax,[ebp+dep_lookahead]
+ cmp eax,edi
+; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+ jae nolookaheadnicematch
+ mov edi,eax
+nolookaheadnicematch:
+; best_len = s->prev_length
+ mov best_len,ebx
+
+; window = s->window
+ mov esi,[ebp+dep_window]
+ mov ecx,[ebp+dep_strstart]
+ mov window,esi
+
+ mov nice_match,edi
+; scan = window + strstart
+ add esi,ecx
+ mov scan,esi
+; dx = *window
+ mov dx,word ptr [esi]
+; bx = *(window+best_len-1)
+ mov bx,word ptr [esi+ebx-1]
+ add esi,MAX_MATCH-1
+; scan_start = *scan
+ mov scan_start,dx
+; strend = scan + MAX_MATCH-1
+ mov strend,esi
+; bx = scan_end = *(window+best_len-1)
+
+; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+; s->strstart - (IPos)MAX_DIST(s) : NIL;
+
+ mov esi,[ebp+dep_w_size]
+ sub esi,MIN_LOOKAHEAD
+; here esi = MAX_DIST(s)
+ sub ecx,esi
+ ja nodist
+ xor ecx,ecx
+nodist:
+ mov limit,ecx
+
+; prev = s->prev
+ mov edx,[ebp+dep_prev]
+ mov prev,edx
+
+;
+ mov edx,dword ptr [ebp+dep_match_start]
+ mov bp,scan_start
+ mov eax,cur_match
+ mov match_start,edx
+
+ mov edx,window
+ mov edi,edx
+ add edi,best_len
+ mov esi,prev
+ dec edi
+; windowlen = window + best_len -1
+ mov windowlen,edi
+
+ jmp beginloop2
+ align 4
+
+; here, in the loop
+; eax = ax = cur_match
+; ecx = limit
+; bx = scan_end
+; bp = scan_start
+; edi = windowlen (window + best_len -1)
+; esi = prev
+
+
+;// here; chain_length <=16
+normalbeg0add16:
+ add chain_length,16
+ jz exitloop
+normalbeg0:
+ cmp word ptr[edi+eax],bx
+ je normalbeg2noroll
+rcontlabnoroll:
+; cur_match = prev[cur_match & wmask]
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+; if cur_match > limit, go to exitloop
+ cmp ecx,eax
+ jnb exitloop
+; if --chain_length != 0, go to exitloop
+ dec chain_length
+ jnz normalbeg0
+ jmp exitloop
+
+normalbeg2noroll:
+; if (scan_start==*(cur_match+window)) goto normalbeg2
+ cmp bp,word ptr[edx+eax]
+ jne rcontlabnoroll
+ jmp normalbeg2
+
+contloop3:
+ mov edi,windowlen
+
+; cur_match = prev[cur_match & wmask]
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+; if cur_match > limit, go to exitloop
+ cmp ecx,eax
+jnbexitloopshort1:
+ jnb exitloop
+; if --chain_length != 0, go to exitloop
+
+
+; begin the main loop
+beginloop2:
+ sub chain_length,16+1
+; if chain_length <=16, don't use the unrolled loop
+ jna normalbeg0add16
+
+do16:
+ cmp word ptr[edi+eax],bx
+ je normalbeg2dc0
+
+maccn MACRO lab
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+ cmp ecx,eax
+ jnb exitloop
+ cmp word ptr[edi+eax],bx
+ je lab
+ ENDM
+
+rcontloop0:
+ maccn normalbeg2dc1
+
+rcontloop1:
+ maccn normalbeg2dc2
+
+rcontloop2:
+ maccn normalbeg2dc3
+
+rcontloop3:
+ maccn normalbeg2dc4
+
+rcontloop4:
+ maccn normalbeg2dc5
+
+rcontloop5:
+ maccn normalbeg2dc6
+
+rcontloop6:
+ maccn normalbeg2dc7
+
+rcontloop7:
+ maccn normalbeg2dc8
+
+rcontloop8:
+ maccn normalbeg2dc9
+
+rcontloop9:
+ maccn normalbeg2dc10
+
+rcontloop10:
+ maccn short normalbeg2dc11
+
+rcontloop11:
+ maccn short normalbeg2dc12
+
+rcontloop12:
+ maccn short normalbeg2dc13
+
+rcontloop13:
+ maccn short normalbeg2dc14
+
+rcontloop14:
+ maccn short normalbeg2dc15
+
+rcontloop15:
+ and eax,7fffh
+ mov ax,word ptr[esi+eax*2]
+ cmp ecx,eax
+ jnb exitloop
+
+ sub chain_length,16
+ ja do16
+ jmp normalbeg0add16
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+normbeg MACRO rcontlab,valsub
+; if we are here, we know that *(match+best_len-1) == scan_end
+ cmp bp,word ptr[edx+eax]
+; if (match != scan_start) goto rcontlab
+ jne rcontlab
+; calculate the good chain_length, and we'll compare scan and match string
+ add chain_length,16-valsub
+ jmp iseq
+ ENDM
+
+
+normalbeg2dc11:
+ normbeg rcontloop11,11
+
+normalbeg2dc12:
+ normbeg short rcontloop12,12
+
+normalbeg2dc13:
+ normbeg short rcontloop13,13
+
+normalbeg2dc14:
+ normbeg short rcontloop14,14
+
+normalbeg2dc15:
+ normbeg short rcontloop15,15
+
+normalbeg2dc10:
+ normbeg rcontloop10,10
+
+normalbeg2dc9:
+ normbeg rcontloop9,9
+
+normalbeg2dc8:
+ normbeg rcontloop8,8
+
+normalbeg2dc7:
+ normbeg rcontloop7,7
+
+normalbeg2dc6:
+ normbeg rcontloop6,6
+
+normalbeg2dc5:
+ normbeg rcontloop5,5
+
+normalbeg2dc4:
+ normbeg rcontloop4,4
+
+normalbeg2dc3:
+ normbeg rcontloop3,3
+
+normalbeg2dc2:
+ normbeg rcontloop2,2
+
+normalbeg2dc1:
+ normbeg rcontloop1,1
+
+normalbeg2dc0:
+ normbeg rcontloop0,0
+
+
+; we go in normalbeg2 because *(ushf*)(match+best_len-1) == scan_end
+
+normalbeg2:
+ mov edi,window
+
+ cmp bp,word ptr[edi+eax]
+ jne contloop3 ; if *(ushf*)match != scan_start, continue
+
+iseq:
+; if we are here, we know that *(match+best_len-1) == scan_end
+; and (match == scan_start)
+
+ mov edi,edx
+ mov esi,scan ; esi = scan
+ add edi,eax ; edi = window + cur_match = match
+
+ mov edx,[esi+3] ; compare manually dword at match+3
+ xor edx,[edi+3] ; and scan +3
+
+ jz begincompare ; if equal, go to long compare
+
+; we will determine the unmatch byte and calculate len (in esi)
+ or dl,dl
+ je eq1rr
+ mov esi,3
+ jmp trfinval
+eq1rr:
+ or dx,dx
+ je eq1
+
+ mov esi,4
+ jmp trfinval
+eq1:
+ and edx,0ffffffh
+ jz eq11
+ mov esi,5
+ jmp trfinval
+eq11:
+ mov esi,6
+ jmp trfinval
+
+begincompare:
+ ; here we now scan and match begin same
+ add edi,6
+ add esi,6
+ mov ecx,(MAX_MATCH-(2+4))/4 ; scan for at most MAX_MATCH bytes
+ repe cmpsd ; loop until mismatch
+
+ je trfin ; go to trfin if not unmatch
+; we determine the unmatch byte
+ sub esi,4
+ mov edx,[edi-4]
+ xor edx,[esi]
+
+ or dl,dl
+ jnz trfin
+ inc esi
+
+ or dx,dx
+ jnz trfin
+ inc esi
+
+ and edx,0ffffffh
+ jnz trfin
+ inc esi
+
+trfin:
+ sub esi,scan ; esi = len
+trfinval:
+; here we have finised compare, and esi contain len of equal string
+ cmp esi,best_len ; if len > best_len, go newbestlen
+ ja short newbestlen
+; now we restore edx, ecx and esi, for the big loop
+ mov esi,prev
+ mov ecx,limit
+ mov edx,window
+ jmp contloop3
+
+newbestlen:
+ mov best_len,esi ; len become best_len
+
+ mov match_start,eax ; save new position as match_start
+ cmp esi,nice_match ; if best_len >= nice_match, exit
+ jae exitloop
+ mov ecx,scan
+ mov edx,window ; restore edx=window
+ add ecx,esi
+ add esi,edx
+
+ dec esi
+ mov windowlen,esi ; windowlen = window + best_len-1
+ mov bx,[ecx-1] ; bx = *(scan+best_len-1) = scan_end
+
+; now we restore ecx and esi, for the big loop :
+ mov esi,prev
+ mov ecx,limit
+ jmp contloop3
+
+exitloop:
+; exit : s->match_start=match_start
+ mov ebx,match_start
+ mov ebp,str_s
+ mov ecx,best_len
+ mov dword ptr [ebp+dep_match_start],ebx
+ mov eax,dword ptr [ebp+dep_lookahead]
+ cmp ecx,eax
+ ja minexlo
+ mov eax,ecx
+minexlo:
+; return min(best_len,s->lookahead)
+
+; restore stack and register ebx,esi,edi,ebp
+ add esp,NbStackAdd
+
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+InfoAuthor:
+; please don't remove this string !
+; Your are free use gvmat32 in any fre or commercial apps if you don't remove the string in the binary!
+ db 0dh,0ah,"GVMat32 optimised assembly code written 1996-98 by Gilles Vollant",0dh,0ah
+
+
+
+IFDEF NOUNDERLINE
+longest_match_7fff endp
+ELSE
+_longest_match_7fff endp
+ENDIF
+
+
+IFDEF NOUNDERLINE
+cpudetect32 proc near
+ELSE
+_cpudetect32 proc near
+ENDIF
+
+
+ pushfd ; push original EFLAGS
+ pop eax ; get original EFLAGS
+ mov ecx, eax ; save original EFLAGS
+ xor eax, 40000h ; flip AC bit in EFLAGS
+ push eax ; save new EFLAGS value on stack
+ popfd ; replace current EFLAGS value
+ pushfd ; get new EFLAGS
+ pop eax ; store new EFLAGS in EAX
+ xor eax, ecx ; can\92t toggle AC bit, processor=80386
+ jz end_cpu_is_386 ; jump if 80386 processor
+ push ecx
+ popfd ; restore AC bit in EFLAGS first
+
+ pushfd
+ pushfd
+ pop ecx
+
+ mov eax, ecx ; get original EFLAGS
+ xor eax, 200000h ; flip ID bit in EFLAGS
+ push eax ; save new EFLAGS value on stack
+ popfd ; replace current EFLAGS value
+ pushfd ; get new EFLAGS
+ pop eax ; store new EFLAGS in EAX
+ popfd ; restore original EFLAGS
+ xor eax, ecx ; can\92t toggle ID bit,
+ je is_old_486 ; processor=old
+
+ mov eax,1
+ db 0fh,0a2h ;CPUID
+
+exitcpudetect:
+ ret
+
+end_cpu_is_386:
+ mov eax,0300h
+ jmp exitcpudetect
+
+is_old_486:
+ mov eax,0400h
+ jmp exitcpudetect
+
+IFDEF NOUNDERLINE
+cpudetect32 endp
+ELSE
+_cpudetect32 endp
+ENDIF
+
+_TEXT ends
+end
--- /dev/null
+/* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86
+ * Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant.
+ * File written by Gilles Vollant, by modifiying the longest_match
+ * from Jean-loup Gailly in deflate.c
+ * it prepare all parameters and call the assembly longest_match_gvasm
+ * longest_match execute standard C code is wmask != 0x7fff
+ * (assembly code is faster with a fixed wmask)
+ *
+ */
+
+#include "deflate.h"
+
+#undef FAR
+#include <windows.h>
+
+#ifdef ASMV
+#define NIL 0
+
+#define UNALIGNED_OK
+
+
+/* if your C compiler don't add underline before function name,
+ define ADD_UNDERLINE_ASMFUNC */
+#ifdef ADD_UNDERLINE_ASMFUNC
+#define longest_match_7fff _longest_match_7fff
+#endif
+
+
+
+void match_init()
+{
+}
+
+unsigned long cpudetect32();
+
+uInt longest_match_c(
+ deflate_state *s,
+ IPos cur_match); /* current match */
+
+
+uInt longest_match_7fff(
+ deflate_state *s,
+ IPos cur_match); /* current match */
+
+uInt longest_match(
+ deflate_state *s,
+ IPos cur_match) /* current match */
+{
+ static uInt iIsPPro=2;
+
+ if ((s->w_mask == 0x7fff) && (iIsPPro==0))
+ return longest_match_7fff(s,cur_match);
+
+ if (iIsPPro==2)
+ iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0;
+
+ return longest_match_c(s,cur_match);
+}
+
+
+
+uInt longest_match_c(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+
+#endif /* ASMV */
--- /dev/null
+c:\masm611\bin\ml /coff /Zi /c /Flgvmat32.lst gvmat32.asm
--- /dev/null
+LIBRARY "zlib"
+
+DESCRIPTION '"""zlib data compression library"""'
+
+
+VERSION 1.11
+
+
+HEAPSIZE 1048576,8192
+
+EXPORTS
+ adler32 @1
+ compress @2
+ crc32 @3
+ deflate @4
+ deflateCopy @5
+ deflateEnd @6
+ deflateInit2_ @7
+ deflateInit_ @8
+ deflateParams @9
+ deflateReset @10
+ deflateSetDictionary @11
+ gzclose @12
+ gzdopen @13
+ gzerror @14
+ gzflush @15
+ gzopen @16
+ gzread @17
+ gzwrite @18
+ inflate @19
+ inflateEnd @20
+ inflateInit2_ @21
+ inflateInit_ @22
+ inflateReset @23
+ inflateSetDictionary @24
+ inflateSync @25
+ uncompress @26
+ zlibVersion @27
+ gzprintf @28
+ gzputc @29
+ gzgetc @30
+ gzseek @31
+ gzrewind @32
+ gztell @33
+ gzeof @34
+ gzsetparams @35
+ zError @36
+ inflateSyncPoint @37
+ get_crc_table @38
+ compress2 @39
+ gzputs @40
+ gzgets @41
+
+ unzOpen @61
+ unzClose @62
+ unzGetGlobalInfo @63
+ unzGetCurrentFileInfo @64
+ unzGoToFirstFile @65
+ unzGoToNextFile @66
+ unzOpenCurrentFile @67
+ unzReadCurrentFile @68
+ unztell @70
+ unzeof @71
+ unzCloseCurrentFile @72
+ unzGetGlobalComment @73
+ unzStringFileNameCompare @74
+ unzLocateFile @75
+ unzGetLocalExtrafield @76
+
+ zipOpen @80
+ zipOpenNewFileInZip @81
+ zipWriteInFileInZip @82
+ zipCloseFileInZip @83
+ zipClose @84
--- /dev/null
+# Microsoft Developer Studio Project File - Name="zlibvc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=zlibvc - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zlibvc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zlibvc.mak" CFG="zlibvc - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zlibvc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseAxp" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutAsm" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutCrtdll" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\zlib.dll"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc__"
+# PROP BASE Intermediate_Dir "zlibvc__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc__"
+# PROP Intermediate_Dir "zlibvc__"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:"zlibvc__\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_0"
+# PROP BASE Intermediate_Dir "zlibvc_0"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_0"
+# PROP Intermediate_Dir "zlibvc_0"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_0\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_1"
+# PROP BASE Intermediate_Dir "zlibvc_1"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_1"
+# PROP Intermediate_Dir "zlibvc_1"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_1\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "zlibvc - Win32 Release"
+# Name "zlibvc - Win32 Debug"
+# Name "zlibvc - Win32 ReleaseAxp"
+# Name "zlibvc - Win32 ReleaseWithoutAsm"
+# Name "zlibvc - Win32 ReleaseWithoutCrtdll"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\adler32.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ADLER=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_COMPR=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\crc32.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_CRC32=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_DEFLA=\
+ ".\deflate.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gvmat32c.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gzio.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_GZIO_=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFBL=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFCO=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inffast.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFFA=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inffast.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFLA=\
+ ".\infblock.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFTR=\
+ ".\inftrees.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFUT=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_TREES=\
+ ".\deflate.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\uncompr.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_UNCOM=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\unzip.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zip.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlibvc.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ZUTIL=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zlibstat"=.\zlibstat.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zlibvc"=.\zlibvc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
--- /dev/null
+This is a patched version of zlib modified to use
+Pentium-optimized assembly code in the deflation algorithm. The files
+changed/added by this patch are:
+
+README.586
+match.S
+
+The effectiveness of these modifications is a bit marginal, as the the
+program's bottleneck seems to be mostly L1-cache contention, for which
+there is no real way to work around without rewriting the basic
+algorithm. The speedup on average is around 5-10% (which is generally
+less than the amount of variance between subsequent executions).
+However, when used at level 9 compression, the cache contention can
+drop enough for the assembly version to achieve 10-20% speedup (and
+sometimes more, depending on the amount of overall redundancy in the
+files). Even here, though, cache contention can still be the limiting
+factor, depending on the nature of the program using the zlib library.
+This may also mean that better improvements will be seen on a Pentium
+with MMX, which suffers much less from L1-cache contention, but I have
+not yet verified this.
+
+Note that this code has been tailored for the Pentium in particular,
+and will not perform well on the Pentium Pro (due to the use of a
+partial register in the inner loop).
+
+If you are using an assembler other than GNU as, you will have to
+translate match.S to use your assembler's syntax. (Have fun.)
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 1998
+
+
+Added for zlib 1.1.3:
+
+The patches come from
+http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+To compile zlib with this asm file, copy match.S to the zlib directory
+then do:
+
+CFLAGS="-O3 -DASMV" ./configure
+make OBJA=match.o
--- /dev/null
+/* match.s -- Pentium-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define match_init _match_init
+#define longest_match _longest_match
+#endif
+
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define wmask 0 /* local copy of s->wmask */
+#define window 4 /* local copy of s->window */
+#define windowbestlen 8 /* s->window + bestlen */
+#define chainlenscanend 12 /* high word: current chain len */
+ /* low word: last bytes sought */
+#define scanstart 16 /* first two bytes of string */
+#define scanalign 20 /* dword-misalignment of string */
+#define nicematch 24 /* a good enough match size */
+#define bestlen 28 /* size of best match so far */
+#define scan 32 /* ptr to string wanting match */
+
+#define LocalVarsSize (36)
+/* saved ebx 36 */
+/* saved edi 40 */
+/* saved esi 44 */
+/* saved ebp 48 */
+/* return address 52 */
+#define deflatestate 56 /* the function arguments */
+#define curmatch 60
+
+/* Offsets for fields in the deflate_state structure. These numbers
+ * are calculated from the definition of deflate_state, with the
+ * assumption that the compiler will dword-align the fields. (Thus,
+ * changing the definition of deflate_state could easily cause this
+ * program to crash horribly, without so much as a warning at
+ * compile time. Sigh.)
+ */
+#define dsWSize 36
+#define dsWMask 44
+#define dsWindow 48
+#define dsPrev 56
+#define dsMatchLen 88
+#define dsPrevMatch 92
+#define dsStrStart 100
+#define dsMatchStart 104
+#define dsLookahead 108
+#define dsPrevLen 112
+#define dsMaxChainLen 116
+#define dsGoodMatch 132
+#define dsNiceMatch 136
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to */
+/* make room for our stack frame. */
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match */
+/* throughout the entire function. %edx will hold the pointer to the */
+/* deflate_state structure during the function's setup (before */
+/* entering the main loop). */
+
+ movl deflatestate(%esp), %edx
+ movl curmatch(%esp), %ecx
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch(%edx), %eax
+ movl dsLookahead(%edx), %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ movl dsWindow(%edx), %esi
+ movl %esi, window(%esp)
+ movl dsStrStart(%edx), %ebp
+ lea (%esi,%ebp), %edi
+ movl %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ movl %edi, %eax
+ negl %eax
+ andl $3, %eax
+ movl %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize(%edx), %eax
+ subl $MIN_LOOKAHEAD, %eax
+ subl %eax, %ebp
+ jg LimitPositive
+ xorl %ebp, %ebp
+LimitPositive:
+
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen(%edx), %eax
+ movl dsGoodMatch(%edx), %ebx
+ cmpl %ebx, %eax
+ movl dsMaxChainLen(%edx), %ebx
+ jl LastMatchGood
+ shrl $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the scanend */
+/* scanend value, which it will always accompany. */
+
+ decl %ebx
+ shll $16, %ebx
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen(%edx), %eax
+ movl %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+
+ movw (%edi), %bx
+ movw %bx, scanstart(%esp)
+ movw -1(%edi,%eax), %bx
+ movl %ebx, chainlenscanend(%esp)
+
+/* Posf *prev = s->prev; */
+/* uInt wmask = s->w_mask; */
+
+ movl dsPrev(%edx), %edi
+ movl dsWMask(%edx), %edx
+ mov %edx, wmask(%esp)
+
+/* Jump into the main loop. */
+
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend)
+ * %ecx = curmatch
+ * %edx = curmatch & wmask
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ *
+ * Two optimization notes on the choice of instructions:
+ *
+ * The first instruction uses a 16-bit address, which costs an extra,
+ * unpairable cycle. This is cheaper than doing a 32-bit access and
+ * zeroing the high word, due to the 3-cycle misalignment penalty which
+ * would occur half the time. This also turns out to be cheaper than
+ * doing two separate 8-bit accesses, as the memory is so rarely in the
+ * L1 cache.
+ *
+ * The window buffer, however, apparently spends a lot of time in the
+ * cache, and so it is faster to retrieve the word at the end of the
+ * match string with two 8-bit loads. The instructions that test the
+ * word at the beginning of the match string, however, are executed
+ * much less frequently, and there it was cheaper to use 16-bit
+ * instructions, which avoided the necessity of saving off and
+ * subsequently reloading one of the other registers.
+ */
+LookupLoop:
+ /* 1 U & V */
+ movw (%edi,%edx,2), %cx /* 2 U pipe */
+ movl wmask(%esp), %edx /* 2 V pipe */
+ cmpl %ebp, %ecx /* 3 U pipe */
+ jbe LeaveNow /* 3 V pipe */
+ subl $0x00010000, %ebx /* 4 U pipe */
+ js LeaveNow /* 4 V pipe */
+LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */
+ andl %ecx, %edx /* 5 V pipe */
+ cmpb %bl, %al /* 6 U pipe */
+ jnz LookupLoop /* 6 V pipe */
+ movb (%esi,%ecx), %ah
+ cmpb %bh, %ah
+ jnz LookupLoop
+ movl window(%esp), %eax
+ movw (%eax,%ecx), %ax
+ cmpw scanstart(%esp), %ax
+ jnz LookupLoop
+
+/* Store the current value of chainlen. */
+
+ movl %ebx, chainlenscanend(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ movl window(%esp), %esi
+ movl scan(%esp), %edi
+ addl %ecx, %esi
+ movl scanalign(%esp), %eax
+ movl $(-MAX_MATCH_8), %edx
+ lea MAX_MATCH_8(%edi,%eax), %edi
+ lea MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+ movl (%esi,%edx), %eax
+ movl (%edi,%edx), %ebx
+ xorl %ebx, %eax
+ jnz LeaveLoopCmps
+ movl 4(%esi,%edx), %eax
+ movl 4(%edi,%edx), %ebx
+ xorl %ebx, %eax
+ jnz LeaveLoopCmps4
+ addl $8, %edx
+ jnz LoopCmps
+ jmp LenMaximum
+LeaveLoopCmps4: addl $4, %edx
+LeaveLoopCmps: testl $0x0000FFFF, %eax
+ jnz LenLower
+ addl $2, %edx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adcl $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%edi,%edx), %eax
+ movl scan(%esp), %edi
+ subl %edi, %eax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ cmpl %ebx, %eax
+ jg LongerMatch
+ movl chainlenscanend(%esp), %ebx
+ movl windowbestlen(%esp), %esi
+ movl dsPrev(%edx), %edi
+ movl wmask(%esp), %edx
+ andl %ecx, %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch: movl nicematch(%esp), %ebx
+ movl %eax, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+ cmpl %ebx, %eax
+ jge LeaveNow
+ movl window(%esp), %esi
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+ movl chainlenscanend(%esp), %ebx
+ movw -1(%edi,%eax), %bx
+ movl dsPrev(%edx), %edi
+ movl %ebx, chainlenscanend(%esp)
+ movl wmask(%esp), %edx
+ andl %ecx, %edx
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum: movl deflatestate(%esp), %edx
+ movl $MAX_MATCH, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ movl dsLookahead(%edx), %eax
+ cmpl %eax, %ebx
+ jg LookaheadRet
+ movl %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came. */
+
+ addl $LocalVarsSize, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+match_init: ret
--- /dev/null
+This is a patched version of zlib, modified to use
+Pentium-Pro-optimized assembly code in the deflation algorithm. The
+files changed/added by this patch are:
+
+README.686
+match.S
+
+The speedup that this patch provides varies, depending on whether the
+compiler used to build the original version of zlib falls afoul of the
+PPro's speed traps. My own tests show a speedup of around 10-20% at
+the default compression level, and 20-30% using -9, against a version
+compiled using gcc 2.7.2.3. Your mileage may vary.
+
+Note that this code has been tailored for the PPro/PII in particular,
+and will not perform particuarly well on a Pentium.
+
+If you are using an assembler other than GNU as, you will have to
+translate match.S to use your assembler's syntax. (Have fun.)
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 1998
+
+
+Added for zlib 1.1.3:
+
+The patches come from
+http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+To compile zlib with this asm file, copy match.S to the zlib directory
+then do:
+
+CFLAGS="-O3 -DASMV" ./configure
+make OBJA=match.o
--- /dev/null
+/* match.s -- Pentium-Pro-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define match_init _match_init
+#define longest_match _longest_match
+#endif
+
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define chainlenwmask 0 /* high word: current chain len */
+ /* low word: s->wmask */
+#define window 4 /* local copy of s->window */
+#define windowbestlen 8 /* s->window + bestlen */
+#define scanstart 16 /* first two bytes of string */
+#define scanend 12 /* last two bytes of string */
+#define scanalign 20 /* dword-misalignment of string */
+#define nicematch 24 /* a good enough match size */
+#define bestlen 28 /* size of best match so far */
+#define scan 32 /* ptr to string wanting match */
+
+#define LocalVarsSize (36)
+/* saved ebx 36 */
+/* saved edi 40 */
+/* saved esi 44 */
+/* saved ebp 48 */
+/* return address 52 */
+#define deflatestate 56 /* the function arguments */
+#define curmatch 60
+
+/* Offsets for fields in the deflate_state structure. These numbers
+ * are calculated from the definition of deflate_state, with the
+ * assumption that the compiler will dword-align the fields. (Thus,
+ * changing the definition of deflate_state could easily cause this
+ * program to crash horribly, without so much as a warning at
+ * compile time. Sigh.)
+ */
+#define dsWSize 36
+#define dsWMask 44
+#define dsWindow 48
+#define dsPrev 56
+#define dsMatchLen 88
+#define dsPrevMatch 92
+#define dsStrStart 100
+#define dsMatchStart 104
+#define dsLookahead 108
+#define dsPrevLen 112
+#define dsMaxChainLen 116
+#define dsGoodMatch 132
+#define dsNiceMatch 136
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to */
+/* make room for our stack frame. */
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match */
+/* throughout the entire function. %edx will hold the pointer to the */
+/* deflate_state structure during the function's setup (before */
+/* entering the main loop). */
+
+ movl deflatestate(%esp), %edx
+ movl curmatch(%esp), %ecx
+
+/* uInt wmask = s->w_mask; */
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen(%edx), %eax
+ movl dsGoodMatch(%edx), %ebx
+ cmpl %ebx, %eax
+ movl dsWMask(%edx), %eax
+ movl dsMaxChainLen(%edx), %ebx
+ jl LastMatchGood
+ shrl $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the wmask */
+/* value, which it will always accompany. */
+
+ decl %ebx
+ shll $16, %ebx
+ orl %eax, %ebx
+ movl %ebx, chainlenwmask(%esp)
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch(%edx), %eax
+ movl dsLookahead(%edx), %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ movl dsWindow(%edx), %esi
+ movl %esi, window(%esp)
+ movl dsStrStart(%edx), %ebp
+ lea (%esi,%ebp), %edi
+ movl %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ movl %edi, %eax
+ negl %eax
+ andl $3, %eax
+ movl %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize(%edx), %eax
+ subl $MIN_LOOKAHEAD, %eax
+ subl %eax, %ebp
+ jg LimitPositive
+ xorl %ebp, %ebp
+LimitPositive:
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen(%edx), %eax
+ movl %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+/* Posf *prev = s->prev; */
+
+ movzwl (%edi), %ebx
+ movl %ebx, scanstart(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl %ebx, scanend(%esp)
+ movl dsPrev(%edx), %edi
+
+/* Jump into the main loop. */
+
+ movl chainlenwmask(%esp), %edx
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = scanend
+ * %ecx = curmatch
+ * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ */
+LookupLoop:
+ andl %edx, %ecx
+ movzwl (%edi,%ecx,2), %ecx
+ cmpl %ebp, %ecx
+ jbe LeaveNow
+ subl $0x00010000, %edx
+ js LeaveNow
+LoopEntry: movzwl -1(%esi,%ecx), %eax
+ cmpl %ebx, %eax
+ jnz LookupLoop
+ movl window(%esp), %eax
+ movzwl (%eax,%ecx), %eax
+ cmpl scanstart(%esp), %eax
+ jnz LookupLoop
+
+/* Store the current value of chainlen. */
+
+ movl %edx, chainlenwmask(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ movl window(%esp), %esi
+ movl scan(%esp), %edi
+ addl %ecx, %esi
+ movl scanalign(%esp), %eax
+ movl $(-MAX_MATCH_8), %edx
+ lea MAX_MATCH_8(%edi,%eax), %edi
+ lea MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+ movl (%esi,%edx), %eax
+ xorl (%edi,%edx), %eax
+ jnz LeaveLoopCmps
+ movl 4(%esi,%edx), %eax
+ xorl 4(%edi,%edx), %eax
+ jnz LeaveLoopCmps4
+ addl $8, %edx
+ jnz LoopCmps
+ jmp LenMaximum
+LeaveLoopCmps4: addl $4, %edx
+LeaveLoopCmps: testl $0x0000FFFF, %eax
+ jnz LenLower
+ addl $2, %edx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adcl $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%edi,%edx), %eax
+ movl scan(%esp), %edi
+ subl %edi, %eax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ cmpl %ebx, %eax
+ jg LongerMatch
+ movl windowbestlen(%esp), %esi
+ movl dsPrev(%edx), %edi
+ movl scanend(%esp), %ebx
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch: movl nicematch(%esp), %ebx
+ movl %eax, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+ cmpl %ebx, %eax
+ jge LeaveNow
+ movl window(%esp), %esi
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl dsPrev(%edx), %edi
+ movl %ebx, scanend(%esp)
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum: movl deflatestate(%esp), %edx
+ movl $MAX_MATCH, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ movl dsLookahead(%edx), %eax
+ cmpl %eax, %ebx
+ jg LookaheadRet
+ movl %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came. */
+
+ addl $LocalVarsSize, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+match_init: ret
--- /dev/null
+# Makefile for zlib32bd.lib
+# ------------- Borland C++ 4.5 -------------
+
+# The (32-bit) zlib32bd.lib made with this makefile is intended for use
+# in making the (32-bit) DLL, png32bd.dll. It uses the "stdcall" calling
+# convention.
+
+CFLAGS= -ps -O2 -C -K -N- -k- -d -3 -r- -w-par -w-aus -WDE
+CC=f:\bc45\bin\bcc32
+LIBFLAGS= /C
+LIB=f:\bc45\bin\tlib
+ZLIB=zlib32bd.lib
+
+.autodepend
+.c.obj:
+ $(CC) -c $(CFLAGS) $<
+
+OBJ1=adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infblock.obj
+OBJ2=infcodes.obj inflate.obj inftrees.obj infutil.obj inffast.obj
+OBJ3=trees.obj uncompr.obj zutil.obj
+pOBJ1=+adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infblock.obj
+pOBJ2=+infcodes.obj+inflate.obj+inftrees.obj+infutil.obj+inffast.obj
+pOBJ3=+trees.obj+uncompr.obj+zutil.obj
+
+all: $(ZLIB)
+
+$(ZLIB): $(OBJ1) $(OBJ2) $(OBJ3)
+ @if exist $@ del $@
+ $(LIB) @&&|
+$@ $(LIBFLAGS) &
+$(pOBJ1) &
+$(pOBJ2) &
+$(pOBJ3)
+|
+
+# End of makefile for zlib32bd.lib
--- /dev/null
+unit zlibdef;
+
+interface
+
+uses
+ Windows;
+
+const
+ ZLIB_VERSION = '1.1.3';
+
+type
+ voidpf = Pointer;
+ int = Integer;
+ uInt = Cardinal;
+ pBytef = PChar;
+ uLong = Cardinal;
+
+ alloc_func = function(opaque: voidpf; items, size: uInt): voidpf;
+ stdcall;
+ free_func = procedure(opaque, address: voidpf);
+ stdcall;
+
+ internal_state = Pointer;
+
+ z_streamp = ^z_stream;
+ z_stream = packed record
+ next_in: pBytef; // next input byte
+ avail_in: uInt; // number of bytes available at next_in
+ total_in: uLong; // total nb of input bytes read so far
+
+ next_out: pBytef; // next output byte should be put there
+ avail_out: uInt; // remaining free space at next_out
+ total_out: uLong; // total nb of bytes output so far
+
+ msg: PChar; // last error message, NULL if no error
+ state: internal_state; // not visible by applications
+
+ zalloc: alloc_func; // used to allocate the internal state
+ zfree: free_func; // used to free the internal state
+ opaque: voidpf; // private data object passed to zalloc and zfree
+
+ data_type: int; // best guess about the data type: ascii or binary
+ adler: uLong; // adler32 value of the uncompressed data
+ reserved: uLong; // reserved for future use
+ end;
+
+const
+ Z_NO_FLUSH = 0;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = -1;
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_DEFAULT_STRATEGY = 0;
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_UNKNOWN = 2;
+
+ Z_DEFLATED = 8;
+
+ MAX_MEM_LEVEL = 9;
+
+function adler32(adler: uLong; const buf: pBytef; len: uInt): uLong;
+ stdcall;
+function crc32(crc: uLong; const buf: pBytef; len: uInt): uLong;
+ stdcall;
+function deflate(strm: z_streamp; flush: int): int;
+ stdcall;
+function deflateCopy(dest, source: z_streamp): int;
+ stdcall;
+function deflateEnd(strm: z_streamp): int;
+ stdcall;
+function deflateInit2_(strm: z_streamp; level, method,
+ windowBits, memLevel, strategy: int;
+ const version: PChar; stream_size: int): int;
+ stdcall;
+function deflateInit_(strm: z_streamp; level: int;
+ const version: PChar; stream_size: int): int;
+ stdcall;
+function deflateParams(strm: z_streamp; level, strategy: int): int;
+ stdcall;
+function deflateReset(strm: z_streamp): int;
+ stdcall;
+function deflateSetDictionary(strm: z_streamp;
+ const dictionary: pBytef;
+ dictLength: uInt): int;
+ stdcall;
+function inflate(strm: z_streamp; flush: int): int;
+ stdcall;
+function inflateEnd(strm: z_streamp): int;
+ stdcall;
+function inflateInit2_(strm: z_streamp; windowBits: int;
+ const version: PChar; stream_size: int): int;
+ stdcall;
+function inflateInit_(strm: z_streamp; const version: PChar;
+ stream_size: int): int;
+ stdcall;
+function inflateReset(strm: z_streamp): int;
+ stdcall;
+function inflateSetDictionary(strm: z_streamp;
+ const dictionary: pBytef;
+ dictLength: uInt): int;
+ stdcall;
+function inflateSync(strm: z_streamp): int;
+ stdcall;
+
+function deflateInit(strm: z_streamp; level: int): int;
+function deflateInit2(strm: z_streamp; level, method, windowBits,
+ memLevel, strategy: int): int;
+function inflateInit(strm: z_streamp): int;
+function inflateInit2(strm: z_streamp; windowBits: int): int;
+
+implementation
+
+function deflateInit(strm: z_streamp; level: int): int;
+begin
+ Result := deflateInit_(strm, level, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function deflateInit2(strm: z_streamp; level, method, windowBits,
+ memLevel, strategy: int): int;
+begin
+ Result := deflateInit2_(strm, level, method, windowBits, memLevel,
+ strategy, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit(strm: z_streamp): int;
+begin
+ Result := inflateInit_(strm, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit2(strm: z_streamp; windowBits: int): int;
+begin
+ Result := inflateInit2_(strm, windowBits, ZLIB_VERSION,
+ sizeof(z_stream));
+end;
+
+const
+ zlibDLL = 'png32bd.dll';
+
+function adler32; external zlibDLL;
+function crc32; external zlibDLL;
+function deflate; external zlibDLL;
+function deflateCopy; external zlibDLL;
+function deflateEnd; external zlibDLL;
+function deflateInit2_; external zlibDLL;
+function deflateInit_; external zlibDLL;
+function deflateParams; external zlibDLL;
+function deflateReset; external zlibDLL;
+function deflateSetDictionary; external zlibDLL;
+function inflate; external zlibDLL;
+function inflateEnd; external zlibDLL;
+function inflateInit2_; external zlibDLL;
+function inflateInit_; external zlibDLL;
+function inflateReset; external zlibDLL;
+function inflateSetDictionary; external zlibDLL;
+function inflateSync; external zlibDLL;
+
+end.
--- /dev/null
+# ---------------------------------------------------------------------------
+!if !$d(BCB)
+BCB = $(MAKEDIR)\..
+!endif
+
+# ---------------------------------------------------------------------------
+# IDE SECTION
+# ---------------------------------------------------------------------------
+# The following section of the project makefile is managed by the BCB IDE.
+# It is recommended to use the IDE to change any of the values in this
+# section.
+# ---------------------------------------------------------------------------
+
+VERSION = BCB.03
+# ---------------------------------------------------------------------------
+PROJECT = d_zlib.lib
+OBJFILES = d_zlib.obj adler32.obj deflate.obj infblock.obj infcodes.obj inffast.obj \
+ inflate.obj inftrees.obj infutil.obj trees.obj
+RESFILES =
+RESDEPEN = $(RESFILES)
+LIBFILES =
+LIBRARIES = VCL35.lib
+SPARELIBS = VCL35.lib
+DEFFILE =
+PACKAGES = VCLX35.bpi VCL35.bpi VCLDB35.bpi VCLDBX35.bpi ibsmp35.bpi bcbsmp35.bpi \
+ dclocx35.bpi QRPT35.bpi TEEUI35.bpi TEEDB35.bpi TEE35.bpi DSS35.bpi \
+ NMFAST35.bpi INETDB35.bpi INET35.bpi VCLMID35.bpi
+# ---------------------------------------------------------------------------
+PATHCPP = .;
+PATHASM = .;
+PATHPAS = .;
+PATHRC = .;
+DEBUGLIBPATH = $(BCB)\lib\debug
+RELEASELIBPATH = $(BCB)\lib\release
+# ---------------------------------------------------------------------------
+CFLAG1 = -O2 -Ve -d -k- -vi
+CFLAG2 = -I$(BCB)\include;$(BCB)\include\vcl -H=$(BCB)\lib\vcl35.csm
+CFLAG3 = -ff -pr -5
+PFLAGS = -U;$(DEBUGLIBPATH) -I$(BCB)\include;$(BCB)\include\vcl -H -W -$I- -v -JPHN -M
+RFLAGS = -i$(BCB)\include;$(BCB)\include\vcl
+AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /mx /w2 /zn
+LFLAGS =
+IFLAGS = -g -Gn
+# ---------------------------------------------------------------------------
+ALLOBJ = c0w32.obj $(OBJFILES)
+ALLRES = $(RESFILES)
+ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib
+# ---------------------------------------------------------------------------
+!!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include
+Item1=$(BCB)\include;$(BCB)\include\vcl
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+ ---------------------------------------------------------------------------
+# MAKE SECTION
+# ---------------------------------------------------------------------------
+# This section of the project file is not used by the BCB IDE. It is for
+# the benefit of building from the command-line using the MAKE utility.
+# ---------------------------------------------------------------------------
+
+.autodepend
+# ---------------------------------------------------------------------------
+!if !$d(BCC32)
+BCC32 = bcc32
+!endif
+
+!if !$d(DCC32)
+DCC32 = dcc32
+!endif
+
+!if !$d(TASM32)
+TASM32 = tasm32
+!endif
+
+!if !$d(LINKER)
+LINKER = TLib
+!endif
+
+!if !$d(BRCC32)
+BRCC32 = brcc32
+!endif
+# ---------------------------------------------------------------------------
+!if $d(PATHCPP)
+.PATH.CPP = $(PATHCPP)
+.PATH.C = $(PATHCPP)
+!endif
+
+!if $d(PATHPAS)
+.PATH.PAS = $(PATHPAS)
+!endif
+
+!if $d(PATHASM)
+.PATH.ASM = $(PATHASM)
+!endif
+
+!if $d(PATHRC)
+.PATH.RC = $(PATHRC)
+!endif
+# ---------------------------------------------------------------------------
+!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include;$(BCB)\include\vcl
+Item1=$(BCB)\include
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
+ $(BCB)\BIN\$(LINKER) @&&!
+ $(LFLAGS) $(IFLAGS) +
+ $(ALLOBJ), +
+ $(PROJECT),, +
+ $(ALLLIB), +
+ $(DEFFILE), +
+ $(ALLRES)
+!
+# ---------------------------------------------------------------------------
+.pas.hpp:
+ $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.pas.obj:
+ $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.cpp.obj:
+ $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.c.obj:
+ $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.asm.obj:
+ $(BCB)\BIN\$(TASM32) $(AFLAGS) $<, $@
+
+.rc.res:
+ $(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $<
+# ---------------------------------------------------------------------------
--- /dev/null
+#include <condefs.h>
+#pragma hdrstop
+//---------------------------------------------------------------------------
+USEUNIT("adler32.c");
+USEUNIT("deflate.c");
+USEUNIT("infblock.c");
+USEUNIT("infcodes.c");
+USEUNIT("inffast.c");
+USEUNIT("inflate.c");
+USEUNIT("inftrees.c");
+USEUNIT("infutil.c");
+USEUNIT("trees.c");
+//---------------------------------------------------------------------------
+#define Library
+
+// To add a file to the library use the Project menu 'Add to Project'.
+
--- /dev/null
+These are files used to compile zlib under Borland C++ Builder 3.
+
+zlib.bpg is the main project group that can be loaded in the BCB IDE and
+loads all other *.bpr projects
+
+zlib.bpr is a project used to create a static zlib.lib library with C calling
+convention for functions.
+
+zlib32.bpr creates a zlib32.dll dynamic link library with Windows standard
+calling convention.
+
+d_zlib.bpr creates a set of .obj files with register calling convention.
+These files are used by zlib.pas to create a Delphi unit containing zlib.
+The d_zlib.lib file generated isn't useful and can be deleted.
+
+zlib.cpp, zlib32.cpp and d_zlib.cpp are used by the above projects.
+
--- /dev/null
+#------------------------------------------------------------------------------
+VERSION = BWS.01
+#------------------------------------------------------------------------------
+!ifndef ROOT
+ROOT = $(MAKEDIR)\..
+!endif
+#------------------------------------------------------------------------------
+MAKE = $(ROOT)\bin\make.exe -$(MAKEFLAGS) -f$**
+DCC = $(ROOT)\bin\dcc32.exe $**
+BRCC = $(ROOT)\bin\brcc32.exe $**
+#------------------------------------------------------------------------------
+PROJECTS = zlib zlib32 d_zlib
+#------------------------------------------------------------------------------
+default: $(PROJECTS)
+#------------------------------------------------------------------------------
+
+zlib: zlib.bpr
+ $(MAKE)
+
+zlib32: zlib32.bpr
+ $(MAKE)
+
+d_zlib: d_zlib.bpr
+ $(MAKE)
+
+
--- /dev/null
+# ---------------------------------------------------------------------------
+!if !$d(BCB)
+BCB = $(MAKEDIR)\..
+!endif
+
+# ---------------------------------------------------------------------------
+# IDE SECTION
+# ---------------------------------------------------------------------------
+# The following section of the project makefile is managed by the BCB IDE.
+# It is recommended to use the IDE to change any of the values in this
+# section.
+# ---------------------------------------------------------------------------
+
+VERSION = BCB.03
+# ---------------------------------------------------------------------------
+PROJECT = zlib.lib
+OBJFILES = zlib.obj adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infblock.obj \
+ infcodes.obj inffast.obj inflate.obj inftrees.obj infutil.obj trees.obj \
+ uncompr.obj zutil.obj
+RESFILES =
+RESDEPEN = $(RESFILES)
+LIBFILES =
+LIBRARIES = VCL35.lib
+SPARELIBS = VCL35.lib
+DEFFILE =
+PACKAGES = VCLX35.bpi VCL35.bpi VCLDB35.bpi VCLDBX35.bpi ibsmp35.bpi bcbsmp35.bpi \
+ dclocx35.bpi QRPT35.bpi TEEUI35.bpi TEEDB35.bpi TEE35.bpi DSS35.bpi \
+ NMFAST35.bpi INETDB35.bpi INET35.bpi VCLMID35.bpi
+# ---------------------------------------------------------------------------
+PATHCPP = .;
+PATHASM = .;
+PATHPAS = .;
+PATHRC = .;
+DEBUGLIBPATH = $(BCB)\lib\debug
+RELEASELIBPATH = $(BCB)\lib\release
+# ---------------------------------------------------------------------------
+CFLAG1 = -O2 -Ve -d -k- -vi
+CFLAG2 = -I$(BCB)\include;$(BCB)\include\vcl -H=$(BCB)\lib\vcl35.csm
+CFLAG3 = -ff -5
+PFLAGS = -U;$(DEBUGLIBPATH) -I$(BCB)\include;$(BCB)\include\vcl -H -W -$I- -v -JPHN -M
+RFLAGS = -i$(BCB)\include;$(BCB)\include\vcl
+AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /mx /w2 /zn
+LFLAGS =
+IFLAGS = -g -Gn
+# ---------------------------------------------------------------------------
+ALLOBJ = c0w32.obj $(OBJFILES)
+ALLRES = $(RESFILES)
+ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib
+# ---------------------------------------------------------------------------
+!!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include
+Item1=$(BCB)\include;$(BCB)\include\vcl
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+ ---------------------------------------------------------------------------
+# MAKE SECTION
+# ---------------------------------------------------------------------------
+# This section of the project file is not used by the BCB IDE. It is for
+# the benefit of building from the command-line using the MAKE utility.
+# ---------------------------------------------------------------------------
+
+.autodepend
+# ---------------------------------------------------------------------------
+!if !$d(BCC32)
+BCC32 = bcc32
+!endif
+
+!if !$d(DCC32)
+DCC32 = dcc32
+!endif
+
+!if !$d(TASM32)
+TASM32 = tasm32
+!endif
+
+!if !$d(LINKER)
+LINKER = TLib
+!endif
+
+!if !$d(BRCC32)
+BRCC32 = brcc32
+!endif
+# ---------------------------------------------------------------------------
+!if $d(PATHCPP)
+.PATH.CPP = $(PATHCPP)
+.PATH.C = $(PATHCPP)
+!endif
+
+!if $d(PATHPAS)
+.PATH.PAS = $(PATHPAS)
+!endif
+
+!if $d(PATHASM)
+.PATH.ASM = $(PATHASM)
+!endif
+
+!if $d(PATHRC)
+.PATH.RC = $(PATHRC)
+!endif
+# ---------------------------------------------------------------------------
+!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include;$(BCB)\include\vcl
+Item1=$(BCB)\include
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
+ $(BCB)\BIN\$(LINKER) @&&!
+ $(LFLAGS) $(IFLAGS) +
+ $(ALLOBJ), +
+ $(PROJECT),, +
+ $(ALLLIB), +
+ $(DEFFILE), +
+ $(ALLRES)
+!
+# ---------------------------------------------------------------------------
+.pas.hpp:
+ $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.pas.obj:
+ $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.cpp.obj:
+ $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.c.obj:
+ $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.asm.obj:
+ $(BCB)\BIN\$(TASM32) $(AFLAGS) $<, $@
+
+.rc.res:
+ $(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $<
+# ---------------------------------------------------------------------------
--- /dev/null
+#include <condefs.h>
+#pragma hdrstop
+//---------------------------------------------------------------------------
+USEUNIT("adler32.c");
+USEUNIT("compress.c");
+USEUNIT("crc32.c");
+USEUNIT("deflate.c");
+USEUNIT("gzio.c");
+USEUNIT("infblock.c");
+USEUNIT("infcodes.c");
+USEUNIT("inffast.c");
+USEUNIT("inflate.c");
+USEUNIT("inftrees.c");
+USEUNIT("infutil.c");
+USEUNIT("trees.c");
+USEUNIT("uncompr.c");
+USEUNIT("zutil.c");
+//---------------------------------------------------------------------------
+#define Library
+
+// To add a file to the library use the Project menu 'Add to Project'.
+
--- /dev/null
+{*******************************************************}
+{ }
+{ Delphi Supplemental Components }
+{ ZLIB Data Compression Interface Unit }
+{ }
+{ Copyright (c) 1997 Borland International }
+{ }
+{*******************************************************}
+
+{ Modified for zlib 1.1.3 by Davide Moretti <dave@rimini.com }
+
+unit zlib;
+
+interface
+
+uses Sysutils, Classes;
+
+type
+ TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer;
+ TFree = procedure (AppData, Block: Pointer);
+
+ // Internal structure. Ignore.
+ TZStreamRec = packed record
+ next_in: PChar; // next input byte
+ avail_in: Integer; // number of bytes available at next_in
+ total_in: Integer; // total nb of input bytes read so far
+
+ next_out: PChar; // next output byte should be put here
+ avail_out: Integer; // remaining free space at next_out
+ total_out: Integer; // total nb of bytes output so far
+
+ msg: PChar; // last error message, NULL if no error
+ internal: Pointer; // not visible by applications
+
+ zalloc: TAlloc; // used to allocate the internal state
+ zfree: TFree; // used to free the internal state
+ AppData: Pointer; // private data object passed to zalloc and zfree
+
+ data_type: Integer; // best guess about the data type: ascii or binary
+ adler: Integer; // adler32 value of the uncompressed data
+ reserved: Integer; // reserved for future use
+ end;
+
+ // Abstract ancestor class
+ TCustomZlibStream = class(TStream)
+ private
+ FStrm: TStream;
+ FStrmPos: Integer;
+ FOnProgress: TNotifyEvent;
+ FZRec: TZStreamRec;
+ FBuffer: array [Word] of Char;
+ protected
+ procedure Progress(Sender: TObject); dynamic;
+ property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
+ constructor Create(Strm: TStream);
+ end;
+
+{ TCompressionStream compresses data on the fly as data is written to it, and
+ stores the compressed data to another stream.
+
+ TCompressionStream is write-only and strictly sequential. Reading from the
+ stream will raise an exception. Using Seek to move the stream pointer
+ will raise an exception.
+
+ Output data is cached internally, written to the output stream only when
+ the internal output buffer is full. All pending output data is flushed
+ when the stream is destroyed.
+
+ The Position property returns the number of uncompressed bytes of
+ data that have been written to the stream so far.
+
+ CompressionRate returns the on-the-fly percentage by which the original
+ data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100
+ If raw data size = 100 and compressed data size = 25, the CompressionRate
+ is 75%
+
+ The OnProgress event is called each time the output buffer is filled and
+ written to the output stream. This is useful for updating a progress
+ indicator when you are writing a large chunk of data to the compression
+ stream in a single call.}
+
+
+ TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+ TCompressionStream = class(TCustomZlibStream)
+ private
+ function GetCompressionRate: Single;
+ public
+ constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property CompressionRate: Single read GetCompressionRate;
+ property OnProgress;
+ end;
+
+{ TDecompressionStream decompresses data on the fly as data is read from it.
+
+ Compressed data comes from a separate source stream. TDecompressionStream
+ is read-only and unidirectional; you can seek forward in the stream, but not
+ backwards. The special case of setting the stream position to zero is
+ allowed. Seeking forward decompresses data until the requested position in
+ the uncompressed data has been reached. Seeking backwards, seeking relative
+ to the end of the stream, requesting the size of the stream, and writing to
+ the stream will raise an exception.
+
+ The Position property returns the number of bytes of uncompressed data that
+ have been read from the stream so far.
+
+ The OnProgress event is called each time the internal input buffer of
+ compressed data is exhausted and the next block is read from the input stream.
+ This is useful for updating a progress indicator when you are reading a
+ large chunk of data from the decompression stream in a single call.}
+
+ TDecompressionStream = class(TCustomZlibStream)
+ public
+ constructor Create(Source: TStream);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property OnProgress;
+ end;
+
+
+
+{ CompressBuf compresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+ OutBytes = number of bytes in OutBuf }
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ out OutBuf: Pointer; out OutBytes: Integer);
+
+
+{ DecompressBuf decompresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ OutEstimate = zero, or est. size of the decompressed data
+ Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+ OutBytes = number of bytes in OutBuf }
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+
+const
+ zlib_version = '1.1.3';
+
+type
+ EZlibError = class(Exception);
+ ECompressionError = class(EZlibError);
+ EDecompressionError = class(EZlibError);
+
+function adler32(adler: Integer; buf: PChar; len: Integer): Integer;
+
+implementation
+
+const
+ Z_NO_FLUSH = 0;
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+ Z_NEED_DICT = 2;
+ Z_ERRNO = (-1);
+ Z_STREAM_ERROR = (-2);
+ Z_DATA_ERROR = (-3);
+ Z_MEM_ERROR = (-4);
+ Z_BUF_ERROR = (-5);
+ Z_VERSION_ERROR = (-6);
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = (-1);
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_DEFAULT_STRATEGY = 0;
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_UNKNOWN = 2;
+
+ Z_DEFLATED = 8;
+
+ _z_errmsg: array[0..9] of PChar = (
+ 'need dictionary', // Z_NEED_DICT (2)
+ 'stream end', // Z_STREAM_END (1)
+ '', // Z_OK (0)
+ 'file error', // Z_ERRNO (-1)
+ 'stream error', // Z_STREAM_ERROR (-2)
+ 'data error', // Z_DATA_ERROR (-3)
+ 'insufficient memory', // Z_MEM_ERROR (-4)
+ 'buffer error', // Z_BUF_ERROR (-5)
+ 'incompatible version', // Z_VERSION_ERROR (-6)
+ ''
+ );
+
+{$L deflate.obj}
+{$L inflate.obj}
+{$L inftrees.obj}
+{$L trees.obj}
+{$L adler32.obj}
+{$L infblock.obj}
+{$L infcodes.obj}
+{$L infutil.obj}
+{$L inffast.obj}
+
+procedure _tr_init; external;
+procedure _tr_tally; external;
+procedure _tr_flush_block; external;
+procedure _tr_align; external;
+procedure _tr_stored_block; external;
+function adler32; external;
+procedure inflate_blocks_new; external;
+procedure inflate_blocks; external;
+procedure inflate_blocks_reset; external;
+procedure inflate_blocks_free; external;
+procedure inflate_set_dictionary; external;
+procedure inflate_trees_bits; external;
+procedure inflate_trees_dynamic; external;
+procedure inflate_trees_fixed; external;
+procedure inflate_codes_new; external;
+procedure inflate_codes; external;
+procedure inflate_codes_free; external;
+procedure _inflate_mask; external;
+procedure inflate_flush; external;
+procedure inflate_fast; external;
+
+procedure _memset(P: Pointer; B: Byte; count: Integer);cdecl;
+begin
+ FillChar(P^, count, B);
+end;
+
+procedure _memcpy(dest, source: Pointer; count: Integer);cdecl;
+begin
+ Move(source^, dest^, count);
+end;
+
+
+
+// deflate compresses data
+function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
+ recsize: Integer): Integer; external;
+function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function deflateEnd(var strm: TZStreamRec): Integer; external;
+
+// inflate decompresses data
+function inflateInit_(var strm: TZStreamRec; version: PChar;
+ recsize: Integer): Integer; external;
+function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function inflateEnd(var strm: TZStreamRec): Integer; external;
+function inflateReset(var strm: TZStreamRec): Integer; external;
+
+
+function zcalloc(AppData: Pointer; Items, Size: Integer): Pointer;
+begin
+ GetMem(Result, Items*Size);
+end;
+
+procedure zcfree(AppData, Block: Pointer);
+begin
+ FreeMem(Block);
+end;
+
+function zlibCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise EZlibError.Create('error'); //!!
+end;
+
+function CCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise ECompressionError.Create('error'); //!!
+end;
+
+function DCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise EDecompressionError.Create('error'); //!!
+end;
+
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ out OutBuf: Pointer; out OutBytes: Integer);
+var
+ strm: TZStreamRec;
+ P: Pointer;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
+ GetMem(OutBuf, OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
+ try
+ while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, 256);
+ ReallocMem(OutBuf, OutBytes);
+ strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := 256;
+ end;
+ finally
+ CCheck(deflateEnd(strm));
+ end;
+ ReallocMem(OutBuf, strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise
+ end;
+end;
+
+
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+var
+ strm: TZStreamRec;
+ P: Pointer;
+ BufInc: Integer;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ BufInc := (InBytes + 255) and not 255;
+ if OutEstimate = 0 then
+ OutBytes := BufInc
+ else
+ OutBytes := OutEstimate;
+ GetMem(OutBuf, OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
+ try
+ while DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, BufInc);
+ ReallocMem(OutBuf, OutBytes);
+ strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := BufInc;
+ end;
+ finally
+ DCheck(inflateEnd(strm));
+ end;
+ ReallocMem(OutBuf, strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise
+ end;
+end;
+
+
+// TCustomZlibStream
+
+constructor TCustomZLibStream.Create(Strm: TStream);
+begin
+ inherited Create;
+ FStrm := Strm;
+ FStrmPos := Strm.Position;
+end;
+
+procedure TCustomZLibStream.Progress(Sender: TObject);
+begin
+ if Assigned(FOnProgress) then FOnProgress(Sender);
+end;
+
+
+// TCompressionStream
+
+constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
+ Dest: TStream);
+const
+ Levels: array [TCompressionLevel] of ShortInt =
+ (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
+begin
+ inherited Create(Dest);
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
+end;
+
+destructor TCompressionStream.Destroy;
+begin
+ FZRec.next_in := nil;
+ FZRec.avail_in := 0;
+ try
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
+ and (FZRec.avail_out = 0) do
+ begin
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ end;
+ if FZRec.avail_out < sizeof(FBuffer) then
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
+ finally
+ deflateEnd(FZRec);
+ end;
+ inherited Destroy;
+end;
+
+function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ raise ECompressionError.Create('Invalid stream operation');
+end;
+
+function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_in := @Buffer;
+ FZRec.avail_in := Count;
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (FZRec.avail_in > 0) do
+ begin
+ CCheck(deflate(FZRec, 0));
+ if FZRec.avail_out = 0 then
+ begin
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ FStrmPos := FStrm.Position;
+ Progress(Self);
+ end;
+ end;
+ Result := Count;
+end;
+
+function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+ if (Offset = 0) and (Origin = soFromCurrent) then
+ Result := FZRec.total_in
+ else
+ raise ECompressionError.Create('Invalid stream operation');
+end;
+
+function TCompressionStream.GetCompressionRate: Single;
+begin
+ if FZRec.total_in = 0 then
+ Result := 0
+ else
+ Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
+end;
+
+
+// TDecompressionStream
+
+constructor TDecompressionStream.Create(Source: TStream);
+begin
+ inherited Create(Source);
+ FZRec.next_in := FBuffer;
+ FZRec.avail_in := 0;
+ DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
+end;
+
+destructor TDecompressionStream.Destroy;
+begin
+ inflateEnd(FZRec);
+ inherited Destroy;
+end;
+
+function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_out := @Buffer;
+ FZRec.avail_out := Count;
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (FZRec.avail_out > 0) do
+ begin
+ if FZRec.avail_in = 0 then
+ begin
+ FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
+ if FZRec.avail_in = 0 then
+ begin
+ Result := Count - FZRec.avail_out;
+ Exit;
+ end;
+ FZRec.next_in := FBuffer;
+ FStrmPos := FStrm.Position;
+ Progress(Self);
+ end;
+ DCheck(inflate(FZRec, 0));
+ end;
+ Result := Count;
+end;
+
+function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ raise EDecompressionError.Create('Invalid stream operation');
+end;
+
+function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+ I: Integer;
+ Buf: array [0..4095] of Char;
+begin
+ if (Offset = 0) and (Origin = soFromBeginning) then
+ begin
+ DCheck(inflateReset(FZRec));
+ FZRec.next_in := FBuffer;
+ FZRec.avail_in := 0;
+ FStrm.Position := 0;
+ FStrmPos := 0;
+ end
+ else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
+ ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
+ begin
+ if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
+ if Offset > 0 then
+ begin
+ for I := 1 to Offset div sizeof(Buf) do
+ ReadBuffer(Buf, sizeof(Buf));
+ ReadBuffer(Buf, Offset mod sizeof(Buf));
+ end;
+ end
+ else
+ raise EDecompressionError.Create('Invalid stream operation');
+ Result := FZRec.total_out;
+end;
+
+end.
--- /dev/null
+# ---------------------------------------------------------------------------
+!if !$d(BCB)
+BCB = $(MAKEDIR)\..
+!endif
+
+# ---------------------------------------------------------------------------
+# IDE SECTION
+# ---------------------------------------------------------------------------
+# The following section of the project makefile is managed by the BCB IDE.
+# It is recommended to use the IDE to change any of the values in this
+# section.
+# ---------------------------------------------------------------------------
+
+VERSION = BCB.03
+# ---------------------------------------------------------------------------
+PROJECT = zlib32.dll
+OBJFILES = zlib32.obj adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infblock.obj \
+ infcodes.obj inffast.obj inflate.obj inftrees.obj infutil.obj trees.obj \
+ uncompr.obj zutil.obj
+RESFILES =
+RESDEPEN = $(RESFILES)
+LIBFILES =
+LIBRARIES =
+SPARELIBS =
+DEFFILE =
+PACKAGES = VCLX35.bpi VCL35.bpi VCLDB35.bpi VCLDBX35.bpi ibsmp35.bpi bcbsmp35.bpi \
+ dclocx35.bpi QRPT35.bpi TEEUI35.bpi TEEDB35.bpi TEE35.bpi DSS35.bpi \
+ NMFAST35.bpi INETDB35.bpi INET35.bpi VCLMID35.bpi
+# ---------------------------------------------------------------------------
+PATHCPP = .;
+PATHASM = .;
+PATHPAS = .;
+PATHRC = .;
+DEBUGLIBPATH = $(BCB)\lib\debug
+RELEASELIBPATH = $(BCB)\lib\release
+# ---------------------------------------------------------------------------
+CFLAG1 = -WD -O2 -Ve -d -k- -vi -c -tWD
+CFLAG2 = -D_NO_VCL;ZLIB_DLL -I$(BCB)\include
+CFLAG3 = -ff -5
+PFLAGS = -D_NO_VCL;ZLIB_DLL -U$(BCB)\lib;$(RELEASELIBPATH) -I$(BCB)\include -$I- -v \
+ -JPHN -M
+RFLAGS = -D_NO_VCL;ZLIB_DLL -i$(BCB)\include
+AFLAGS = /i$(BCB)\include /d_NO_VCL /dZLIB_DLL /mx /w2 /zn
+LFLAGS = -L$(BCB)\lib;$(RELEASELIBPATH) -aa -Tpd -x -Gi
+IFLAGS = -Gn -g
+# ---------------------------------------------------------------------------
+ALLOBJ = c0d32.obj $(OBJFILES)
+ALLRES = $(RESFILES)
+ALLLIB = $(LIBFILES) import32.lib cw32mt.lib
+# ---------------------------------------------------------------------------
+!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=1
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=DLL (GUI)
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=1
+Item0=$(BCB)\include
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib
+
+[HistoryLists\hlConditionals]
+Count=1
+Item0=_NO_VCL;ZLIB_DLL
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+# ---------------------------------------------------------------------------
+# MAKE SECTION
+# ---------------------------------------------------------------------------
+# This section of the project file is not used by the BCB IDE. It is for
+# the benefit of building from the command-line using the MAKE utility.
+# ---------------------------------------------------------------------------
+
+.autodepend
+# ---------------------------------------------------------------------------
+!if !$d(BCC32)
+BCC32 = bcc32
+!endif
+
+!if !$d(DCC32)
+DCC32 = dcc32
+!endif
+
+!if !$d(TASM32)
+TASM32 = tasm32
+!endif
+
+!if !$d(LINKER)
+LINKER = ilink32
+!endif
+
+!if !$d(BRCC32)
+BRCC32 = brcc32
+!endif
+# ---------------------------------------------------------------------------
+!if $d(PATHCPP)
+.PATH.CPP = $(PATHCPP)
+.PATH.C = $(PATHCPP)
+!endif
+
+!if $d(PATHPAS)
+.PATH.PAS = $(PATHPAS)
+!endif
+
+!if $d(PATHASM)
+.PATH.ASM = $(PATHASM)
+!endif
+
+!if $d(PATHRC)
+.PATH.RC = $(PATHRC)
+!endif
+# ---------------------------------------------------------------------------
+$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
+ $(BCB)\BIN\$(LINKER) @&&!
+ $(LFLAGS) $(IFLAGS) +
+ $(ALLOBJ), +
+ $(PROJECT),, +
+ $(ALLLIB), +
+ $(DEFFILE), +
+ $(ALLRES)
+!
+# ---------------------------------------------------------------------------
+.pas.hpp:
+ $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.pas.obj:
+ $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.cpp.obj:
+ $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.c.obj:
+ $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.asm.obj:
+ $(BCB)\BIN\$(TASM32) $(AFLAGS) $<, $@
+
+.rc.res:
+ $(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $<
+# ---------------------------------------------------------------------------
--- /dev/null
+
+#include <windows.h>
+#pragma hdrstop
+#include <condefs.h>
+
+
+//---------------------------------------------------------------------------
+// Important note about DLL memory management in a VCL DLL:
+//
+//
+//
+// If your DLL uses VCL and exports any functions that pass VCL String objects
+// (or structs/classes containing nested Strings) as parameter or function
+// results, you will need to build both your DLL project and any EXE projects
+// that use your DLL with the dynamic RTL (the RTL DLL). This will change your
+// DLL and its calling EXE's to use BORLNDMM.DLL as their memory manager. In
+// these cases, the file BORLNDMM.DLL should be deployed along with your DLL
+// and the RTL DLL (CP3240MT.DLL). To avoid the requiring BORLNDMM.DLL in
+// these situations, pass string information using "char *" or ShortString
+// parameters and then link with the static RTL.
+//
+//---------------------------------------------------------------------------
+USEUNIT("adler32.c");
+USEUNIT("compress.c");
+USEUNIT("crc32.c");
+USEUNIT("deflate.c");
+USEUNIT("gzio.c");
+USEUNIT("infblock.c");
+USEUNIT("infcodes.c");
+USEUNIT("inffast.c");
+USEUNIT("inflate.c");
+USEUNIT("inftrees.c");
+USEUNIT("infutil.c");
+USEUNIT("trees.c");
+USEUNIT("uncompr.c");
+USEUNIT("zutil.c");
+//---------------------------------------------------------------------------
+#pragma argsused
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+{
+ return 1;
+}
--- /dev/null
+
+#include "zfstream.h"
+
+int main() {
+
+ // Construct a stream object with this filebuffer. Anything sent
+ // to this stream will go to standard out.
+ gzofstream os( 1, ios::out );
+
+ // This text is getting compressed and sent to stdout.
+ // To prove this, run 'test | zcat'.
+ os << "Hello, Mommy" << endl;
+
+ os << setcompressionlevel( Z_NO_COMPRESSION );
+ os << "hello, hello, hi, ho!" << endl;
+
+ setcompressionlevel( os, Z_DEFAULT_COMPRESSION )
+ << "I'm compressing again" << endl;
+
+ os.close();
+
+ return 0;
+
+}
--- /dev/null
+
+#include <memory.h>
+#include "zfstream.h"
+
+gzfilebuf::gzfilebuf() :
+ file(NULL),
+ mode(0),
+ own_file_descriptor(0)
+{ }
+
+gzfilebuf::~gzfilebuf() {
+
+ sync();
+ if ( own_file_descriptor )
+ close();
+
+}
+
+gzfilebuf *gzfilebuf::open( const char *name,
+ int io_mode ) {
+
+ if ( is_open() )
+ return NULL;
+
+ char char_mode[10];
+ char *p;
+ memset(char_mode,'\0',10);
+ p = char_mode;
+
+ if ( io_mode & ios::in ) {
+ mode = ios::in;
+ *p++ = 'r';
+ } else if ( io_mode & ios::app ) {
+ mode = ios::app;
+ *p++ = 'a';
+ } else {
+ mode = ios::out;
+ *p++ = 'w';
+ }
+
+ if ( io_mode & ios::binary ) {
+ mode |= ios::binary;
+ *p++ = 'b';
+ }
+
+ // Hard code the compression level
+ if ( io_mode & (ios::out|ios::app )) {
+ *p++ = '9';
+ }
+
+ if ( (file = gzopen(name, char_mode)) == NULL )
+ return NULL;
+
+ own_file_descriptor = 1;
+
+ return this;
+
+}
+
+gzfilebuf *gzfilebuf::attach( int file_descriptor,
+ int io_mode ) {
+
+ if ( is_open() )
+ return NULL;
+
+ char char_mode[10];
+ char *p;
+ memset(char_mode,'\0',10);
+ p = char_mode;
+
+ if ( io_mode & ios::in ) {
+ mode = ios::in;
+ *p++ = 'r';
+ } else if ( io_mode & ios::app ) {
+ mode = ios::app;
+ *p++ = 'a';
+ } else {
+ mode = ios::out;
+ *p++ = 'w';
+ }
+
+ if ( io_mode & ios::binary ) {
+ mode |= ios::binary;
+ *p++ = 'b';
+ }
+
+ // Hard code the compression level
+ if ( io_mode & (ios::out|ios::app )) {
+ *p++ = '9';
+ }
+
+ if ( (file = gzdopen(file_descriptor, char_mode)) == NULL )
+ return NULL;
+
+ own_file_descriptor = 0;
+
+ return this;
+
+}
+
+gzfilebuf *gzfilebuf::close() {
+
+ if ( is_open() ) {
+
+ sync();
+ gzclose( file );
+ file = NULL;
+
+ }
+
+ return this;
+
+}
+
+int gzfilebuf::setcompressionlevel( short comp_level ) {
+
+ return gzsetparams(file, comp_level, -2);
+
+}
+
+int gzfilebuf::setcompressionstrategy( short comp_strategy ) {
+
+ return gzsetparams(file, -2, comp_strategy);
+
+}
+
+
+streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) {
+
+ return streampos(EOF);
+
+}
+
+int gzfilebuf::underflow() {
+
+ // If the file hasn't been opened for reading, error.
+ if ( !is_open() || !(mode & ios::in) )
+ return EOF;
+
+ // if a buffer doesn't exists, allocate one.
+ if ( !base() ) {
+
+ if ( (allocate()) == EOF )
+ return EOF;
+ setp(0,0);
+
+ } else {
+
+ if ( in_avail() )
+ return (unsigned char) *gptr();
+
+ if ( out_waiting() ) {
+ if ( flushbuf() == EOF )
+ return EOF;
+ }
+
+ }
+
+ // Attempt to fill the buffer.
+
+ int result = fillbuf();
+ if ( result == EOF ) {
+ // disable get area
+ setg(0,0,0);
+ return EOF;
+ }
+
+ return (unsigned char) *gptr();
+
+}
+
+int gzfilebuf::overflow( int c ) {
+
+ if ( !is_open() || !(mode & ios::out) )
+ return EOF;
+
+ if ( !base() ) {
+ if ( allocate() == EOF )
+ return EOF;
+ setg(0,0,0);
+ } else {
+ if (in_avail()) {
+ return EOF;
+ }
+ if (out_waiting()) {
+ if (flushbuf() == EOF)
+ return EOF;
+ }
+ }
+
+ int bl = blen();
+ setp( base(), base() + bl);
+
+ if ( c != EOF ) {
+
+ *pptr() = c;
+ pbump(1);
+
+ }
+
+ return 0;
+
+}
+
+int gzfilebuf::sync() {
+
+ if ( !is_open() )
+ return EOF;
+
+ if ( out_waiting() )
+ return flushbuf();
+
+ return 0;
+
+}
+
+int gzfilebuf::flushbuf() {
+
+ int n;
+ char *q;
+
+ q = pbase();
+ n = pptr() - q;
+
+ if ( gzwrite( file, q, n) < n )
+ return EOF;
+
+ setp(0,0);
+
+ return 0;
+
+}
+
+int gzfilebuf::fillbuf() {
+
+ int required;
+ char *p;
+
+ p = base();
+
+ required = blen();
+
+ int t = gzread( file, p, required );
+
+ if ( t <= 0) return EOF;
+
+ setg( base(), base(), base()+t);
+
+ return t;
+
+}
+
+gzfilestream_common::gzfilestream_common() :
+ ios( gzfilestream_common::rdbuf() )
+{ }
+
+gzfilestream_common::~gzfilestream_common()
+{ }
+
+void gzfilestream_common::attach( int fd, int io_mode ) {
+
+ if ( !buffer.attach( fd, io_mode) )
+ clear( ios::failbit | ios::badbit );
+ else
+ clear();
+
+}
+
+void gzfilestream_common::open( const char *name, int io_mode ) {
+
+ if ( !buffer.open( name, io_mode ) )
+ clear( ios::failbit | ios::badbit );
+ else
+ clear();
+
+}
+
+void gzfilestream_common::close() {
+
+ if ( !buffer.close() )
+ clear( ios::failbit | ios::badbit );
+
+}
+
+gzfilebuf *gzfilestream_common::rdbuf() {
+
+ return &buffer;
+
+}
+
+gzifstream::gzifstream() :
+ ios( gzfilestream_common::rdbuf() )
+{
+ clear( ios::badbit );
+}
+
+gzifstream::gzifstream( const char *name, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::open( name, io_mode );
+}
+
+gzifstream::gzifstream( int fd, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::attach( fd, io_mode );
+}
+
+gzifstream::~gzifstream() { }
+
+gzofstream::gzofstream() :
+ ios( gzfilestream_common::rdbuf() )
+{
+ clear( ios::badbit );
+}
+
+gzofstream::gzofstream( const char *name, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::open( name, io_mode );
+}
+
+gzofstream::gzofstream( int fd, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::attach( fd, io_mode );
+}
+
+gzofstream::~gzofstream() { }
--- /dev/null
+
+#ifndef _zfstream_h
+#define _zfstream_h
+
+#include <fstream.h>
+#include "zlib.h"
+
+class gzfilebuf : public streambuf {
+
+public:
+
+ gzfilebuf( );
+ virtual ~gzfilebuf();
+
+ gzfilebuf *open( const char *name, int io_mode );
+ gzfilebuf *attach( int file_descriptor, int io_mode );
+ gzfilebuf *close();
+
+ int setcompressionlevel( short comp_level );
+ int setcompressionstrategy( short comp_strategy );
+
+ inline int is_open() const { return (file !=NULL); }
+
+ virtual streampos seekoff( streamoff, ios::seek_dir, int );
+
+ virtual int sync();
+
+protected:
+
+ virtual int underflow();
+ virtual int overflow( int = EOF );
+
+private:
+
+ gzFile file;
+ short mode;
+ short own_file_descriptor;
+
+ int flushbuf();
+ int fillbuf();
+
+};
+
+class gzfilestream_common : virtual public ios {
+
+ friend class gzifstream;
+ friend class gzofstream;
+ friend gzofstream &setcompressionlevel( gzofstream &, int );
+ friend gzofstream &setcompressionstrategy( gzofstream &, int );
+
+public:
+ virtual ~gzfilestream_common();
+
+ void attach( int fd, int io_mode );
+ void open( const char *name, int io_mode );
+ void close();
+
+protected:
+ gzfilestream_common();
+
+private:
+ gzfilebuf *rdbuf();
+
+ gzfilebuf buffer;
+
+};
+
+class gzifstream : public gzfilestream_common, public istream {
+
+public:
+
+ gzifstream();
+ gzifstream( const char *name, int io_mode = ios::in );
+ gzifstream( int fd, int io_mode = ios::in );
+
+ virtual ~gzifstream();
+
+};
+
+class gzofstream : public gzfilestream_common, public ostream {
+
+public:
+
+ gzofstream();
+ gzofstream( const char *name, int io_mode = ios::out );
+ gzofstream( int fd, int io_mode = ios::out );
+
+ virtual ~gzofstream();
+
+};
+
+template<class T> class gzomanip {
+ friend gzofstream &operator<<(gzofstream &, const gzomanip<T> &);
+public:
+ gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { }
+private:
+ gzofstream &(*func)(gzofstream &, T);
+ T val;
+};
+
+template<class T> gzofstream &operator<<(gzofstream &s,
+ const gzomanip<T> &m) {
+ return (*m.func)(s, m.val);
+
+}
+
+inline gzofstream &setcompressionlevel( gzofstream &s, int l ) {
+ (s.rdbuf())->setcompressionlevel(l);
+ return s;
+}
+
+inline gzofstream &setcompressionstrategy( gzofstream &s, int l ) {
+ (s.rdbuf())->setcompressionstrategy(l);
+ return s;
+}
+
+inline gzomanip<int> setcompressionlevel(int l)
+{
+ return gzomanip<int>(&setcompressionlevel,l);
+}
+
+inline gzomanip<int> setcompressionstrategy(int l)
+{
+ return gzomanip<int>(&setcompressionstrategy,l);
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*
+ *
+ * Copyright (c) 1997
+ * Christian Michelsen Research AS
+ * Advanced Computing
+ * Fantoftvegen 38, 5036 BERGEN, Norway
+ * http://www.cmr.no
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Christian Michelsen Research AS makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef ZSTREAM__H
+#define ZSTREAM__H
+
+/*
+ * zstream.h - C++ interface to the 'zlib' general purpose compression library
+ * $Id$
+ */
+
+#include <strstream.h>
+#include <string.h>
+#include <stdio.h>
+#include "zlib.h"
+
+#if defined(_WIN32)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+class zstringlen {
+public:
+ zstringlen(class izstream&);
+ zstringlen(class ozstream&, const char*);
+ size_t value() const { return val.word; }
+private:
+ struct Val { unsigned char byte; size_t word; } val;
+};
+
+// ----------------------------- izstream -----------------------------
+
+class izstream
+{
+ public:
+ izstream() : m_fp(0) {}
+ izstream(FILE* fp) : m_fp(0) { open(fp); }
+ izstream(const char* name) : m_fp(0) { open(name); }
+ ~izstream() { close(); }
+
+ /* Opens a gzip (.gz) file for reading.
+ * open() can be used to read a file which is not in gzip format;
+ * in this case read() will directly read from the file without
+ * decompression. errno can be checked to distinguish two error
+ * cases (if errno is zero, the zlib error is Z_MEM_ERROR).
+ */
+ void open(const char* name) {
+ if (m_fp) close();
+ m_fp = ::gzopen(name, "rb");
+ }
+
+ void open(FILE* fp) {
+ SET_BINARY_MODE(fp);
+ if (m_fp) close();
+ m_fp = ::gzdopen(fileno(fp), "rb");
+ }
+
+ /* Flushes all pending input if necessary, closes the compressed file
+ * and deallocates all the (de)compression state. The return value is
+ * the zlib error number (see function error() below).
+ */
+ int close() {
+ int r = ::gzclose(m_fp);
+ m_fp = 0; return r;
+ }
+
+ /* Binary read the given number of bytes from the compressed file.
+ */
+ int read(void* buf, size_t len) {
+ return ::gzread(m_fp, buf, len);
+ }
+
+ /* Returns the error message for the last error which occurred on the
+ * given compressed file. errnum is set to zlib error number. If an
+ * error occurred in the file system and not in the compression library,
+ * errnum is set to Z_ERRNO and the application may consult errno
+ * to get the exact error code.
+ */
+ const char* error(int* errnum) {
+ return ::gzerror(m_fp, errnum);
+ }
+
+ gzFile fp() { return m_fp; }
+
+ private:
+ gzFile m_fp;
+};
+
+/*
+ * Binary read the given (array of) object(s) from the compressed file.
+ * If the input file was not in gzip format, read() copies the objects number
+ * of bytes into the buffer.
+ * returns the number of uncompressed bytes actually read
+ * (0 for end of file, -1 for error).
+ */
+template <class T, class Items>
+inline int read(izstream& zs, T* x, Items items) {
+ return ::gzread(zs.fp(), x, items*sizeof(T));
+}
+
+/*
+ * Binary input with the '>' operator.
+ */
+template <class T>
+inline izstream& operator>(izstream& zs, T& x) {
+ ::gzread(zs.fp(), &x, sizeof(T));
+ return zs;
+}
+
+
+inline zstringlen::zstringlen(izstream& zs) {
+ zs > val.byte;
+ if (val.byte == 255) zs > val.word;
+ else val.word = val.byte;
+}
+
+/*
+ * Read length of string + the string with the '>' operator.
+ */
+inline izstream& operator>(izstream& zs, char* x) {
+ zstringlen len(zs);
+ ::gzread(zs.fp(), x, len.value());
+ x[len.value()] = '\0';
+ return zs;
+}
+
+inline char* read_string(izstream& zs) {
+ zstringlen len(zs);
+ char* x = new char[len.value()+1];
+ ::gzread(zs.fp(), x, len.value());
+ x[len.value()] = '\0';
+ return x;
+}
+
+// ----------------------------- ozstream -----------------------------
+
+class ozstream
+{
+ public:
+ ozstream() : m_fp(0), m_os(0) {
+ }
+ ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION)
+ : m_fp(0), m_os(0) {
+ open(fp, level);
+ }
+ ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION)
+ : m_fp(0), m_os(0) {
+ open(name, level);
+ }
+ ~ozstream() {
+ close();
+ }
+
+ /* Opens a gzip (.gz) file for writing.
+ * The compression level parameter should be in 0..9
+ * errno can be checked to distinguish two error cases
+ * (if errno is zero, the zlib error is Z_MEM_ERROR).
+ */
+ void open(const char* name, int level = Z_DEFAULT_COMPRESSION) {
+ char mode[4] = "wb\0";
+ if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+ if (m_fp) close();
+ m_fp = ::gzopen(name, mode);
+ }
+
+ /* open from a FILE pointer.
+ */
+ void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) {
+ SET_BINARY_MODE(fp);
+ char mode[4] = "wb\0";
+ if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+ if (m_fp) close();
+ m_fp = ::gzdopen(fileno(fp), mode);
+ }
+
+ /* Flushes all pending output if necessary, closes the compressed file
+ * and deallocates all the (de)compression state. The return value is
+ * the zlib error number (see function error() below).
+ */
+ int close() {
+ if (m_os) {
+ ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+ delete[] m_os->str(); delete m_os; m_os = 0;
+ }
+ int r = ::gzclose(m_fp); m_fp = 0; return r;
+ }
+
+ /* Binary write the given number of bytes into the compressed file.
+ */
+ int write(const void* buf, size_t len) {
+ return ::gzwrite(m_fp, (voidp) buf, len);
+ }
+
+ /* Flushes all pending output into the compressed file. The parameter
+ * _flush is as in the deflate() function. The return value is the zlib
+ * error number (see function gzerror below). flush() returns Z_OK if
+ * the flush_ parameter is Z_FINISH and all output could be flushed.
+ * flush() should be called only when strictly necessary because it can
+ * degrade compression.
+ */
+ int flush(int _flush) {
+ os_flush();
+ return ::gzflush(m_fp, _flush);
+ }
+
+ /* Returns the error message for the last error which occurred on the
+ * given compressed file. errnum is set to zlib error number. If an
+ * error occurred in the file system and not in the compression library,
+ * errnum is set to Z_ERRNO and the application may consult errno
+ * to get the exact error code.
+ */
+ const char* error(int* errnum) {
+ return ::gzerror(m_fp, errnum);
+ }
+
+ gzFile fp() { return m_fp; }
+
+ ostream& os() {
+ if (m_os == 0) m_os = new ostrstream;
+ return *m_os;
+ }
+
+ void os_flush() {
+ if (m_os && m_os->pcount()>0) {
+ ostrstream* oss = new ostrstream;
+ oss->fill(m_os->fill());
+ oss->flags(m_os->flags());
+ oss->precision(m_os->precision());
+ oss->width(m_os->width());
+ ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+ delete[] m_os->str(); delete m_os; m_os = oss;
+ }
+ }
+
+ private:
+ gzFile m_fp;
+ ostrstream* m_os;
+};
+
+/*
+ * Binary write the given (array of) object(s) into the compressed file.
+ * returns the number of uncompressed bytes actually written
+ * (0 in case of error).
+ */
+template <class T, class Items>
+inline int write(ozstream& zs, const T* x, Items items) {
+ return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T));
+}
+
+/*
+ * Binary output with the '<' operator.
+ */
+template <class T>
+inline ozstream& operator<(ozstream& zs, const T& x) {
+ ::gzwrite(zs.fp(), (voidp) &x, sizeof(T));
+ return zs;
+}
+
+inline zstringlen::zstringlen(ozstream& zs, const char* x) {
+ val.byte = 255; val.word = ::strlen(x);
+ if (val.word < 255) zs < (val.byte = val.word);
+ else zs < val;
+}
+
+/*
+ * Write length of string + the string with the '<' operator.
+ */
+inline ozstream& operator<(ozstream& zs, const char* x) {
+ zstringlen len(zs, x);
+ ::gzwrite(zs.fp(), (voidp) x, len.value());
+ return zs;
+}
+
+#ifdef _MSC_VER
+inline ozstream& operator<(ozstream& zs, char* const& x) {
+ return zs < (const char*) x;
+}
+#endif
+
+/*
+ * Ascii write with the << operator;
+ */
+template <class T>
+inline ostream& operator<<(ozstream& zs, const T& x) {
+ zs.os_flush();
+ return zs.os() << x;
+}
+
+#endif
--- /dev/null
+#include "zstream.h"
+#include <math.h>
+#include <stdlib.h>
+#include <iomanip.h>
+
+void main() {
+ char h[256] = "Hello";
+ char* g = "Goodbye";
+ ozstream out("temp.gz");
+ out < "This works well" < h < g;
+ out.close();
+
+ izstream in("temp.gz"); // read it back
+ char *x = read_string(in), *y = new char[256], z[256];
+ in > y > z;
+ in.close();
+ cout << x << endl << y << endl << z << endl;
+
+ out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results
+ out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl;
+ out << z << endl << y << endl << x << endl;
+ out << 1.1234567890123456789 << endl;
+
+ delete[] x; delete[] y;
+}
--- /dev/null
+Change in 0.15: (19 Mar 98)
+- fix memory leak in minizip.c
+
+Change in 0.14: (10 Mar 98)
+- fix bugs in minizip.c sample for zipping big file
+- fix problem in month in date handling
+- fix bug in unzlocal_GetCurrentFileInfoInternal in unzip.c for
+ comment handling
+
+Change in 0.13: (6 Mar 98)
+- fix bugs in zip.c
+- add real minizip sample
+
+Change in 0.12: (4 Mar 98)
+- add zip.c and zip.h for creates .zip file
+- fix change_file_date in miniunz.c for Unix (Jean-loup Gailly)
+- fix miniunz.c for file without specific record for directory
+
+Change in 0.11: (3 Mar 98)
+- fix bug in unzGetCurrentFileInfo for get extra field and comment
+- enhance miniunz sample, remove the bad unztst.c sample
+
+Change in 0.10: (2 Mar 98)
+- fix bug in unzReadCurrentFile
+- rename unzip* to unz* function and structure
+- remove Windows-like hungary notation variable name
+- modify some structure in unzip.h
+- add somes comment in source
+- remove unzipGetcCurrentFile function
+- replace ZUNZEXPORT by ZEXPORT
+- add unzGetLocalExtrafield for get the local extrafield info
+- add a new sample, miniunz.c
+
+Change in 0.4: (25 Feb 98)
+- suppress the type unzipFileInZip.
+ Only on file in the zipfile can be open at the same time
+- fix somes typo in code
+- added tm_unz structure in unzip_file_info (date/time in readable format)
--- /dev/null
+CC=cc
+CFLAGS=-O -I../..
+
+UNZ_OBJS = miniunz.o unzip.o ../../libz.a
+ZIP_OBJS = minizip.o zip.o ../../libz.a
+
+.c.o:
+ $(CC) -c $(CFLAGS) $*.c
+
+all: miniunz minizip
+
+miniunz: $(UNZ_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS)
+
+minizip: $(ZIP_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS)
+
+test: miniunz minizip
+ ./minizip test readme.txt
+ ./miniunz -l test.zip
+ mv readme.txt readme.old
+ ./miniunz test.zip
+
+clean:
+ /bin/rm -f *.o *~ minizip miniunz
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "unzip.h"
+
+#define CASESENSITIVITY (0)
+#define WRITEBUFFERSIZE (8192)
+
+/*
+ mini unzip, demo of unzip package
+
+ usage :
+ Usage : miniunz [-exvlo] file.zip [file_to_extract]
+
+ list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
+ if it exists
+*/
+
+
+/* change_file_date : change the date/time of a file
+ filename : the filename of the file where date/time must be modified
+ dosdate : the new date at the MSDos format (4 bytes)
+ tmu_date : the SAME new date at the tm_unz format */
+void change_file_date(filename,dosdate,tmu_date)
+ const char *filename;
+ uLong dosdate;
+ tm_unz tmu_date;
+{
+#ifdef WIN32
+ HANDLE hFile;
+ FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
+
+ hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,
+ 0,NULL,OPEN_EXISTING,0,NULL);
+ GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
+ DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
+ LocalFileTimeToFileTime(&ftLocal,&ftm);
+ SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
+ CloseHandle(hFile);
+#else
+#ifdef unix
+ struct utimbuf ut;
+ struct tm newdate;
+ newdate.tm_sec = tmu_date.tm_sec;
+ newdate.tm_min=tmu_date.tm_min;
+ newdate.tm_hour=tmu_date.tm_hour;
+ newdate.tm_mday=tmu_date.tm_mday;
+ newdate.tm_mon=tmu_date.tm_mon;
+ if (tmu_date.tm_year > 1900)
+ newdate.tm_year=tmu_date.tm_year - 1900;
+ else
+ newdate.tm_year=tmu_date.tm_year ;
+ newdate.tm_isdst=-1;
+
+ ut.actime=ut.modtime=mktime(&newdate);
+ utime(filename,&ut);
+#endif
+#endif
+}
+
+
+/* mymkdir and change_file_date are not 100 % portable
+ As I don't know well Unix, I wait feedback for the unix portion */
+
+int mymkdir(dirname)
+ const char* dirname;
+{
+ int ret=0;
+#ifdef WIN32
+ ret = mkdir(dirname);
+#else
+#ifdef unix
+ ret = mkdir (dirname,0775);
+#endif
+#endif
+ return ret;
+}
+
+int makedir (newdir)
+ char *newdir;
+{
+ char *buffer ;
+ char *p;
+ int len = strlen(newdir);
+
+ if (len <= 0)
+ return 0;
+
+ buffer = (char*)malloc(len+1);
+ strcpy(buffer,newdir);
+
+ if (buffer[len-1] == '/') {
+ buffer[len-1] = '\0';
+ }
+ if (mymkdir(buffer) == 0)
+ {
+ free(buffer);
+ return 1;
+ }
+
+ p = buffer+1;
+ while (1)
+ {
+ char hold;
+
+ while(*p && *p != '\\' && *p != '/')
+ p++;
+ hold = *p;
+ *p = 0;
+ if ((mymkdir(buffer) == -1) && (errno == ENOENT))
+ {
+ printf("couldn't create directory %s\n",buffer);
+ free(buffer);
+ return 0;
+ }
+ if (hold == 0)
+ break;
+ *p++ = hold;
+ }
+ free(buffer);
+ return 1;
+}
+
+void do_banner()
+{
+ printf("MiniUnz 0.15, demo of zLib + Unz package written by Gilles Vollant\n");
+ printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n\n");
+}
+
+void do_help()
+{
+ printf("Usage : miniunz [-exvlo] file.zip [file_to_extract]\n\n") ;
+}
+
+
+int do_list(uf)
+ unzFile uf;
+{
+ uLong i;
+ unz_global_info gi;
+ int err;
+
+ err = unzGetGlobalInfo (uf,&gi);
+ if (err!=UNZ_OK)
+ printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+ printf(" Length Method Size Ratio Date Time CRC-32 Name\n");
+ printf(" ------ ------ ---- ----- ---- ---- ------ ----\n");
+ for (i=0;i<gi.number_entry;i++)
+ {
+ char filename_inzip[256];
+ unz_file_info file_info;
+ uLong ratio=0;
+ const char *string_method;
+ err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+ break;
+ }
+ if (file_info.uncompressed_size>0)
+ ratio = (file_info.compressed_size*100)/file_info.uncompressed_size;
+
+ if (file_info.compression_method==0)
+ string_method="Stored";
+ else
+ if (file_info.compression_method==Z_DEFLATED)
+ {
+ uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
+ if (iLevel==0)
+ string_method="Defl:N";
+ else if (iLevel==1)
+ string_method="Defl:X";
+ else if ((iLevel==2) || (iLevel==3))
+ string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
+ }
+ else
+ string_method="Unkn. ";
+
+ printf("%7lu %6s %7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n",
+ file_info.uncompressed_size,string_method,file_info.compressed_size,
+ ratio,
+ (uLong)file_info.tmu_date.tm_mon + 1,
+ (uLong)file_info.tmu_date.tm_mday,
+ (uLong)file_info.tmu_date.tm_year % 100,
+ (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
+ (uLong)file_info.crc,filename_inzip);
+ if ((i+1)<gi.number_entry)
+ {
+ err = unzGoToNextFile(uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGoToNextFile\n",err);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite)
+ unzFile uf;
+ const int* popt_extract_without_path;
+ int* popt_overwrite;
+{
+ char filename_inzip[256];
+ char* filename_withoutpath;
+ char* p;
+ int err=UNZ_OK;
+ FILE *fout=NULL;
+ void* buf;
+ uInt size_buf;
+
+ unz_file_info file_info;
+ uLong ratio=0;
+ err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+ return err;
+ }
+
+ size_buf = WRITEBUFFERSIZE;
+ buf = (void*)malloc(size_buf);
+ if (buf==NULL)
+ {
+ printf("Error allocating memory\n");
+ return UNZ_INTERNALERROR;
+ }
+
+ p = filename_withoutpath = filename_inzip;
+ while ((*p) != '\0')
+ {
+ if (((*p)=='/') || ((*p)=='\\'))
+ filename_withoutpath = p+1;
+ p++;
+ }
+
+ if ((*filename_withoutpath)=='\0')
+ {
+ if ((*popt_extract_without_path)==0)
+ {
+ printf("creating directory: %s\n",filename_inzip);
+ mymkdir(filename_inzip);
+ }
+ }
+ else
+ {
+ const char* write_filename;
+ int skip=0;
+
+ if ((*popt_extract_without_path)==0)
+ write_filename = filename_inzip;
+ else
+ write_filename = filename_withoutpath;
+
+ err = unzOpenCurrentFile(uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzOpenCurrentFile\n",err);
+ }
+
+ if (((*popt_overwrite)==0) && (err==UNZ_OK))
+ {
+ char rep;
+ FILE* ftestexist;
+ ftestexist = fopen(write_filename,"rb");
+ if (ftestexist!=NULL)
+ {
+ fclose(ftestexist);
+ do
+ {
+ char answer[128];
+ printf("The file %s exist. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
+ scanf("%1s",answer);
+ rep = answer[0] ;
+ if ((rep>='a') && (rep<='z'))
+ rep -= 0x20;
+ }
+ while ((rep!='Y') && (rep!='N') && (rep!='A'));
+ }
+
+ if (rep == 'N')
+ skip = 1;
+
+ if (rep == 'A')
+ *popt_overwrite=1;
+ }
+
+ if ((skip==0) && (err==UNZ_OK))
+ {
+ fout=fopen(write_filename,"wb");
+
+ /* some zipfile don't contain directory alone before file */
+ if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
+ (filename_withoutpath!=(char*)filename_inzip))
+ {
+ char c=*(filename_withoutpath-1);
+ *(filename_withoutpath-1)='\0';
+ makedir(write_filename);
+ *(filename_withoutpath-1)=c;
+ fout=fopen(write_filename,"wb");
+ }
+
+ if (fout==NULL)
+ {
+ printf("error opening %s\n",write_filename);
+ }
+ }
+
+ if (fout!=NULL)
+ {
+ printf(" extracting: %s\n",write_filename);
+
+ do
+ {
+ err = unzReadCurrentFile(uf,buf,size_buf);
+ if (err<0)
+ {
+ printf("error %d with zipfile in unzReadCurrentFile\n",err);
+ break;
+ }
+ if (err>0)
+ if (fwrite(buf,err,1,fout)!=1)
+ {
+ printf("error in writing extracted file\n");
+ err=UNZ_ERRNO;
+ break;
+ }
+ }
+ while (err>0);
+ fclose(fout);
+ if (err==0)
+ change_file_date(write_filename,file_info.dosDate,
+ file_info.tmu_date);
+ }
+
+ if (err==UNZ_OK)
+ {
+ err = unzCloseCurrentFile (uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzCloseCurrentFile\n",err);
+ }
+ }
+ else
+ unzCloseCurrentFile(uf); /* don't lose the error */
+ }
+
+ free(buf);
+ return err;
+}
+
+
+int do_extract(uf,opt_extract_without_path,opt_overwrite)
+ unzFile uf;
+ int opt_extract_without_path;
+ int opt_overwrite;
+{
+ uLong i;
+ unz_global_info gi;
+ int err;
+ FILE* fout=NULL;
+
+ err = unzGetGlobalInfo (uf,&gi);
+ if (err!=UNZ_OK)
+ printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+
+ for (i=0;i<gi.number_entry;i++)
+ {
+ if (do_extract_currentfile(uf,&opt_extract_without_path,
+ &opt_overwrite) != UNZ_OK)
+ break;
+
+ if ((i+1)<gi.number_entry)
+ {
+ err = unzGoToNextFile(uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGoToNextFile\n",err);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite)
+ unzFile uf;
+ const char* filename;
+ int opt_extract_without_path;
+ int opt_overwrite;
+{
+ int err = UNZ_OK;
+ if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
+ {
+ printf("file %s not found in the zipfile\n",filename);
+ return 2;
+ }
+
+ if (do_extract_currentfile(uf,&opt_extract_without_path,
+ &opt_overwrite) == UNZ_OK)
+ return 0;
+ else
+ return 1;
+}
+
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ const char *zipfilename=NULL;
+ const char *filename_to_extract=NULL;
+ int i;
+ int opt_do_list=0;
+ int opt_do_extract=1;
+ int opt_do_extract_withoutpath=0;
+ int opt_overwrite=0;
+ char filename_try[512];
+ unzFile uf=NULL;
+
+ do_banner();
+ if (argc==1)
+ {
+ do_help();
+ exit(0);
+ }
+ else
+ {
+ for (i=1;i<argc;i++)
+ {
+ if ((*argv[i])=='-')
+ {
+ const char *p=argv[i]+1;
+
+ while ((*p)!='\0')
+ {
+ char c=*(p++);;
+ if ((c=='l') || (c=='L'))
+ opt_do_list = 1;
+ if ((c=='v') || (c=='V'))
+ opt_do_list = 1;
+ if ((c=='x') || (c=='X'))
+ opt_do_extract = 1;
+ if ((c=='e') || (c=='E'))
+ opt_do_extract = opt_do_extract_withoutpath = 1;
+ if ((c=='o') || (c=='O'))
+ opt_overwrite=1;
+ }
+ }
+ else
+ {
+ if (zipfilename == NULL)
+ zipfilename = argv[i];
+ else if (filename_to_extract==NULL)
+ filename_to_extract = argv[i] ;
+ }
+ }
+ }
+
+ if (zipfilename!=NULL)
+ {
+ strcpy(filename_try,zipfilename);
+ uf = unzOpen(zipfilename);
+ if (uf==NULL)
+ {
+ strcat(filename_try,".zip");
+ uf = unzOpen(filename_try);
+ }
+ }
+
+ if (uf==NULL)
+ {
+ printf("Cannot open %s or %s.zip\n",zipfilename,zipfilename);
+ exit (1);
+ }
+ printf("%s opened\n",filename_try);
+
+ if (opt_do_list==1)
+ return do_list(uf);
+ else if (opt_do_extract==1)
+ {
+ if (filename_to_extract == NULL)
+ return do_extract(uf,opt_do_extract_withoutpath,opt_overwrite);
+ else
+ return do_extract_onefile(uf,filename_to_extract,
+ opt_do_extract_withoutpath,opt_overwrite);
+ }
+ unzCloseCurrentFile(uf);
+
+ return 0; /* to avoid warning */
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "zip.h"
+
+
+#define WRITEBUFFERSIZE (16384)
+#define MAXFILENAME (256)
+
+#ifdef WIN32
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ int ret = 0;
+ {
+ FILETIME ftLocal;
+ HANDLE hFind;
+ WIN32_FIND_DATA ff32;
+
+ hFind = FindFirstFile(f,&ff32);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
+ FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
+ FindClose(hFind);
+ ret = 1;
+ }
+ }
+ return ret;
+}
+#else
+#ifdef unix
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ int ret=0;
+ struct stat s; /* results of stat() */
+ struct tm* filedate;
+ time_t tm_t=0;
+
+ if (strcmp(f,"-")!=0)
+ {
+ char name[MAXFILENAME];
+ int len = strlen(f);
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (stat(name,&s)==0)
+ {
+ tm_t = s.st_mtime;
+ ret = 1;
+ }
+ }
+ filedate = localtime(&tm_t);
+
+ tmzip->tm_sec = filedate->tm_sec;
+ tmzip->tm_min = filedate->tm_min;
+ tmzip->tm_hour = filedate->tm_hour;
+ tmzip->tm_mday = filedate->tm_mday;
+ tmzip->tm_mon = filedate->tm_mon ;
+ tmzip->tm_year = filedate->tm_year;
+
+ return ret;
+}
+#else
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ return 0;
+}
+#endif
+#endif
+
+
+
+
+int check_exist_file(filename)
+ const char* filename;
+{
+ FILE* ftestexist;
+ int ret = 1;
+ ftestexist = fopen(filename,"rb");
+ if (ftestexist==NULL)
+ ret = 0;
+ else
+ fclose(ftestexist);
+ return ret;
+}
+
+void do_banner()
+{
+ printf("MiniZip 0.15, demo of zLib + Zip package written by Gilles Vollant\n");
+ printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n\n");
+}
+
+void do_help()
+{
+ printf("Usage : minizip [-o] file.zip [files_to_add]\n\n") ;
+}
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ int opt_overwrite=0;
+ int opt_compress_level=Z_DEFAULT_COMPRESSION;
+ int zipfilenamearg = 0;
+ char filename_try[MAXFILENAME];
+ int zipok;
+ int err=0;
+ int size_buf=0;
+ void* buf=NULL,
+
+
+ do_banner();
+ if (argc==1)
+ {
+ do_help();
+ exit(0);
+ return 0;
+ }
+ else
+ {
+ for (i=1;i<argc;i++)
+ {
+ if ((*argv[i])=='-')
+ {
+ const char *p=argv[i]+1;
+
+ while ((*p)!='\0')
+ {
+ char c=*(p++);;
+ if ((c=='o') || (c=='O'))
+ opt_overwrite = 1;
+ if ((c>='0') && (c<='9'))
+ opt_compress_level = c-'0';
+ }
+ }
+ else
+ if (zipfilenamearg == 0)
+ zipfilenamearg = i ;
+ }
+ }
+
+ size_buf = WRITEBUFFERSIZE;
+ buf = (void*)malloc(size_buf);
+ if (buf==NULL)
+ {
+ printf("Error allocating memory\n");
+ return ZIP_INTERNALERROR;
+ }
+
+ if (zipfilenamearg==0)
+ zipok=0;
+ else
+ {
+ int i,len;
+ int dot_found=0;
+
+ zipok = 1 ;
+ strcpy(filename_try,argv[zipfilenamearg]);
+ len=strlen(filename_try);
+ for (i=0;i<len;i++)
+ if (filename_try[i]=='.')
+ dot_found=1;
+
+ if (dot_found==0)
+ strcat(filename_try,".zip");
+
+ if (opt_overwrite==0)
+ if (check_exist_file(filename_try)!=0)
+ {
+ char rep;
+ do
+ {
+ char answer[128];
+ printf("The file %s exist. Overwrite ? [y]es, [n]o : ",filename_try);
+ scanf("%1s",answer);
+ rep = answer[0] ;
+ if ((rep>='a') && (rep<='z'))
+ rep -= 0x20;
+ }
+ while ((rep!='Y') && (rep!='N'));
+ if (rep=='N')
+ zipok = 0;
+ }
+ }
+
+ if (zipok==1)
+ {
+ zipFile zf;
+ int errclose;
+ zf = zipOpen(filename_try,0);
+ if (zf == NULL)
+ {
+ printf("error opening %s\n",filename_try);
+ err= ZIP_ERRNO;
+ }
+ else
+ printf("creating %s\n",filename_try);
+
+ for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++)
+ {
+ if (((*(argv[i]))!='-') && ((*(argv[i]))!='/'))
+ {
+ FILE * fin;
+ int size_read;
+ const char* filenameinzip = argv[i];
+ zip_fileinfo zi;
+
+ zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
+ zi.tmz_date.tm_mday = zi.tmz_date.tm_min = zi.tmz_date.tm_year = 0;
+ zi.dosDate = 0;
+ zi.internal_fa = 0;
+ zi.external_fa = 0;
+ filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
+
+
+ err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
+ NULL,0,NULL,0,NULL /* comment*/,
+ (opt_compress_level != 0) ? Z_DEFLATED : 0,
+ opt_compress_level);
+
+ if (err != ZIP_OK)
+ printf("error in opening %s in zipfile\n",filenameinzip);
+ else
+ {
+ fin = fopen(filenameinzip,"rb");
+ if (fin==NULL)
+ {
+ err=ZIP_ERRNO;
+ printf("error in opening %s for reading\n",filenameinzip);
+ }
+ }
+
+ if (err == ZIP_OK)
+ do
+ {
+ err = ZIP_OK;
+ size_read = fread(buf,1,size_buf,fin);
+ if (size_read < size_buf)
+ if (feof(fin)==0)
+ {
+ printf("error in reading %s\n",filenameinzip);
+ err = ZIP_ERRNO;
+ }
+
+ if (size_read>0)
+ {
+ err = zipWriteInFileInZip (zf,buf,size_read);
+ if (err<0)
+ {
+ printf("error in writing %s in the zipfile\n",
+ filenameinzip);
+ }
+
+ }
+ } while ((err == ZIP_OK) && (size_read>0));
+
+ fclose(fin);
+ if (err<0)
+ err=ZIP_ERRNO;
+ else
+ {
+ err = zipCloseFileInZip(zf);
+ if (err!=ZIP_OK)
+ printf("error in closing %s in the zipfile\n",
+ filenameinzip);
+ }
+ }
+ }
+ errclose = zipClose(zf,NULL);
+ if (errclose != ZIP_OK)
+ printf("error in closing %s\n",filename_try);
+ }
+
+ free(buf);
+ exit(0);
+ return 0; /* to avoid warning */
+}
--- /dev/null
+
+UnZip 0.15 additionnal library
+
+
+ This unzip package allow extract file from .ZIP file, compatible with
+PKZip 2.04g, WinZip, InfoZip tools and compatible.
+
+ Multi volume ZipFile (span) are not supported, and old compression used by old
+PKZip 1.x are not supported.
+
+See probdesc.zip from PKWare for specification of .ZIP format.
+
+What is Unzip
+ The Zlib library support the deflate compression and the creation of gzip (.gz)
+file. Zlib is free and small.
+ The .Zip format, which can contain several compressed files (.gz can containt
+only one file) is a very popular format. This is why I've written a package for reading file compressed in Zipfile.
+
+Using Unzip package
+
+You need source of Zlib (get zlib111.zip and read zlib.h).
+Get unzlb015.zip and read unzip.h (whith documentation of unzip functions)
+
+The Unzip package is only two file : unzip.h and unzip.c. But it use the Zlib
+ files.
+unztst.c is a simple sample program, which list file in a zipfile and display
+ README.TXT or FILE_ID.DIZ (if these files are found).
+miniunz.c is a mini unzip program.
+
+I'm also currenlyt writing a zipping portion (zip.h, zip.c and test with minizip.c)
+
+Please email me for feedback.
+I hope my source is compatible with Unix system, but I need your help for be sure
+
+Latest revision : Mar 04th, 1998
+
+Check http://www.winimage.com/zLibDll/unzip.html for up to date info.
--- /dev/null
+/* unzip.c -- IO on .zip files using zlib
+ Version 0.15 beta, Mar 19th, 1998,
+
+ Read unzip.h for more info
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+
+#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
+ !defined(CASESENSITIVITYDEFAULT_NO)
+#define CASESENSITIVITYDEFAULT_NO
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+const char unz_copyright[] =
+ " unzip 0.15 Copyright 1998 Gilles Vollant ";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info_internal_s
+{
+ uLong offset_curfile;/* relative offset of local header 4 bytes */
+} unz_file_info_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+ when reading and decompress it */
+typedef struct
+{
+ char *read_buffer; /* internal buffer for compressed data */
+ z_stream stream; /* zLib stream structure for inflate */
+
+ uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
+ uLong stream_initialised; /* flag set if stream structure is initialised*/
+
+ uLong offset_local_extrafield;/* offset of the local extra field */
+ uInt size_local_extrafield;/* size of the local extra field */
+ uLong pos_local_extrafield; /* position in the local extra field in read*/
+
+ uLong crc32; /* crc32 of all data uncompressed */
+ uLong crc32_wait; /* crc32 we must obtain after decompress all */
+ uLong rest_read_compressed; /* number of byte to be decompressed */
+ uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+ FILE* file; /* io structore of the zipfile */
+ uLong compression_method; /* compression method (0==store) */
+ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+} file_in_zip_read_info_s;
+
+
+/* unz_s contain internal information about the zipfile
+*/
+typedef struct
+{
+ FILE* file; /* io structore of the zipfile */
+ unz_global_info gi; /* public global information */
+ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ uLong num_file; /* number of the current file in the zipfile*/
+ uLong pos_in_central_dir; /* pos of the current file in the central dir*/
+ uLong current_file_ok; /* flag about the usability of the current file*/
+ uLong central_pos; /* position of the beginning of the central dir*/
+
+ uLong size_central_dir; /* size of the central directory */
+ uLong offset_central_dir; /* offset of start of central directory with
+ respect to the starting disk number */
+
+ unz_file_info cur_file_info; /* public info about the current file in zip*/
+ unz_file_info_internal cur_file_info_internal; /* private info about it*/
+ file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
+ file if we are decompressing it */
+} unz_s;
+
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unzlocal_getByte(fin,pi)
+ FILE *fin;
+ int *pi;
+{
+ unsigned char c;
+ int err = fread(&c, 1, 1, fin);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return UNZ_OK;
+ }
+ else
+ {
+ if (ferror(fin))
+ return UNZ_ERRNO;
+ else
+ return UNZ_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int unzlocal_getShort (fin,pX)
+ FILE* fin;
+ uLong *pX;
+{
+ uLong x ;
+ int i;
+ int err;
+
+ err = unzlocal_getByte(fin,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(fin,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unzlocal_getLong (fin,pX)
+ FILE* fin;
+ uLong *pX;
+{
+ uLong x ;
+ int i;
+ int err;
+
+ err = unzlocal_getByte(fin,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(fin,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(fin,&i);
+ x += ((uLong)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unzlocal_getByte(fin,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (fileName1,fileName2)
+ const char* fileName1;
+ const char* fileName2;
+{
+ for (;;)
+ {
+ char c1=*(fileName1++);
+ char c2=*(fileName2++);
+ if ((c1>='a') && (c1<='z'))
+ c1 -= 0x20;
+ if ((c2>='a') && (c2<='z'))
+ c2 -= 0x20;
+ if (c1=='\0')
+ return ((c2=='\0') ? 0 : -1);
+ if (c2=='\0')
+ return 1;
+ if (c1<c2)
+ return -1;
+ if (c1>c2)
+ return 1;
+ }
+}
+
+
+#ifdef CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
+ const char* fileName1;
+ const char* fileName2;
+ int iCaseSensitivity;
+{
+ if (iCaseSensitivity==0)
+ iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+ if (iCaseSensitivity==1)
+ return strcmp(fileName1,fileName2);
+
+ return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+}
+
+#define BUFREADCOMMENT (0x400)
+
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local uLong unzlocal_SearchCentralDir(fin)
+ FILE *fin;
+{
+ unsigned char* buf;
+ uLong uSizeFile;
+ uLong uBackRead;
+ uLong uMaxBack=0xffff; /* maximum size of global comment */
+ uLong uPosFound=0;
+
+ if (fseek(fin,0,SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ftell( fin );
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize,uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
+ if (fseek(fin,uReadPos,SEEK_SET)!=0)
+ break;
+
+ if (fread(buf,(uInt)uReadSize,1,fin)!=1)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
+ "zlib/zlib109.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+extern unzFile ZEXPORT unzOpen (path)
+ const char *path;
+{
+ unz_s us;
+ unz_s *s;
+ uLong central_pos,uL;
+ FILE * fin ;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ uLong number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+
+ int err=UNZ_OK;
+
+ if (unz_copyright[0]!=' ')
+ return NULL;
+
+ fin=fopen(path,"rb");
+ if (fin==NULL)
+ return NULL;
+
+ central_pos = unzlocal_SearchCentralDir(fin);
+ if (central_pos==0)
+ err=UNZ_ERRNO;
+
+ if (fseek(fin,central_pos,SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unzlocal_getLong(fin,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central dir */
+ if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* zipfile comment length */
+ if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
+ (err==UNZ_OK))
+ err=UNZ_BADZIPFILE;
+
+ if (err!=UNZ_OK)
+ {
+ fclose(fin);
+ return NULL;
+ }
+
+ us.file=fin;
+ us.byte_before_the_zipfile = central_pos -
+ (us.offset_central_dir+us.size_central_dir);
+ us.central_pos = central_pos;
+ us.pfile_in_zip_read = NULL;
+
+
+ s=(unz_s*)ALLOC(sizeof(unz_s));
+ *s=us;
+ unzGoToFirstFile((unzFile)s);
+ return (unzFile)s;
+}
+
+
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (file)
+ unzFile file;
+{
+ unz_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+
+ if (s->pfile_in_zip_read!=NULL)
+ unzCloseCurrentFile(file);
+
+ fclose(s->file);
+ TRYFREE(s);
+ return UNZ_OK;
+}
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
+ unzFile file;
+ unz_global_info *pglobal_info;
+{
+ unz_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ *pglobal_info=s->gi;
+ return UNZ_OK;
+}
+
+
+/*
+ Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
+ uLong ulDosDate;
+ tm_unz* ptm;
+{
+ uLong uDate;
+ uDate = (uLong)(ulDosDate>>16);
+ ptm->tm_mday = (uInt)(uDate&0x1f) ;
+ ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+ ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+ ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+ ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
+ ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+ Get Info about the current file in the zipfile, with internal only info
+*/
+local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
+ unz_file_info *pfile_info,
+ unz_file_info_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+local int unzlocal_GetCurrentFileInfoInternal (file,
+ pfile_info,
+ pfile_info_internal,
+ szFileName, fileNameBufferSize,
+ extraField, extraFieldBufferSize,
+ szComment, commentBufferSize)
+ unzFile file;
+ unz_file_info *pfile_info;
+ unz_file_info_internal *pfile_info_internal;
+ char *szFileName;
+ uLong fileNameBufferSize;
+ void *extraField;
+ uLong extraFieldBufferSize;
+ char *szComment;
+ uLong commentBufferSize;
+{
+ unz_s* s;
+ unz_file_info file_info;
+ unz_file_info_internal file_info_internal;
+ int err=UNZ_OK;
+ uLong uMagic;
+ long lSeek=0;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+
+ /* we check the magic */
+ if (err==UNZ_OK)
+ if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x02014b50)
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+ if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ lSeek+=file_info.size_filename;
+ if ((err==UNZ_OK) && (szFileName!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_filename<fileNameBufferSize)
+ {
+ *(szFileName+file_info.size_filename)='\0';
+ uSizeRead = file_info.size_filename;
+ }
+ else
+ uSizeRead = fileNameBufferSize;
+
+ if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+ if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
+ err=UNZ_ERRNO;
+ lSeek -= uSizeRead;
+ }
+
+
+ if ((err==UNZ_OK) && (extraField!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_file_extra<extraFieldBufferSize)
+ uSizeRead = file_info.size_file_extra;
+ else
+ uSizeRead = extraFieldBufferSize;
+
+ if (lSeek!=0)
+ if (fseek(s->file,lSeek,SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+ if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
+ err=UNZ_ERRNO;
+ lSeek += file_info.size_file_extra - uSizeRead;
+ }
+ else
+ lSeek+=file_info.size_file_extra;
+
+
+ if ((err==UNZ_OK) && (szComment!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_file_comment<commentBufferSize)
+ {
+ *(szComment+file_info.size_file_comment)='\0';
+ uSizeRead = file_info.size_file_comment;
+ }
+ else
+ uSizeRead = commentBufferSize;
+
+ if (lSeek!=0)
+ if (fseek(s->file,lSeek,SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+ if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
+ err=UNZ_ERRNO;
+ lSeek+=file_info.size_file_comment - uSizeRead;
+ }
+ else
+ lSeek+=file_info.size_file_comment;
+
+ if ((err==UNZ_OK) && (pfile_info!=NULL))
+ *pfile_info=file_info;
+
+ if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+ *pfile_info_internal=file_info_internal;
+
+ return err;
+}
+
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo (file,
+ pfile_info,
+ szFileName, fileNameBufferSize,
+ extraField, extraFieldBufferSize,
+ szComment, commentBufferSize)
+ unzFile file;
+ unz_file_info *pfile_info;
+ char *szFileName;
+ uLong fileNameBufferSize;
+ void *extraField;
+ uLong extraFieldBufferSize;
+ char *szComment;
+ uLong commentBufferSize;
+{
+ return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+}
+
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (file)
+ unzFile file;
+{
+ int err=UNZ_OK;
+ unz_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ s->pos_in_central_dir=s->offset_central_dir;
+ s->num_file=0;
+ err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (file)
+ unzFile file;
+{
+ unz_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (s->num_file+1==s->gi.number_entry)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+ s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+ s->num_file++;
+ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzipStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
+ unzFile file;
+ const char *szFileName;
+ int iCaseSensitivity;
+{
+ unz_s* s;
+ int err;
+
+
+ uLong num_fileSaved;
+ uLong pos_in_central_dirSaved;
+
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+
+ if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+ return UNZ_PARAMERROR;
+
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ num_fileSaved = s->num_file;
+ pos_in_central_dirSaved = s->pos_in_central_dir;
+
+ err = unzGoToFirstFile(file);
+
+ while (err == UNZ_OK)
+ {
+ char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+ unzGetCurrentFileInfo(file,NULL,
+ szCurrentFileName,sizeof(szCurrentFileName)-1,
+ NULL,0,NULL,0);
+ if (unzStringFileNameCompare(szCurrentFileName,
+ szFileName,iCaseSensitivity)==0)
+ return UNZ_OK;
+ err = unzGoToNextFile(file);
+ }
+
+ s->num_file = num_fileSaved ;
+ s->pos_in_central_dir = pos_in_central_dirSaved ;
+ return err;
+}
+
+
+/*
+ Read the local header of the current zipfile
+ Check the coherency of the local header and info in the end of central
+ directory about this file
+ store in *piSizeVar the size of extra info in local header
+ (filename and size of extra field data)
+*/
+local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
+ poffset_local_extrafield,
+ psize_local_extrafield)
+ unz_s* s;
+ uInt* piSizeVar;
+ uLong *poffset_local_extrafield;
+ uInt *psize_local_extrafield;
+{
+ uLong uMagic,uData,uFlags;
+ uLong size_filename;
+ uLong size_extra_field;
+ int err=UNZ_OK;
+
+ *piSizeVar = 0;
+ *poffset_local_extrafield = 0;
+ *psize_local_extrafield = 0;
+
+ if (fseek(s->file,s->cur_file_info_internal.offset_curfile +
+ s->byte_before_the_zipfile,SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+
+ if (err==UNZ_OK)
+ if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x04034b50)
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+/*
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+ err=UNZ_BADZIPFILE;
+*/
+ if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+ err=UNZ_BADZIPFILE;
+
+ if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
+ err=UNZ_ERRNO;
+
+ if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
+ ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
+ ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
+ ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+
+ if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+ err=UNZ_BADZIPFILE;
+
+ *piSizeVar += (uInt)size_filename;
+
+ if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
+ err=UNZ_ERRNO;
+ *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+ SIZEZIPLOCALHEADER + size_filename;
+ *psize_local_extrafield = (uInt)size_extra_field;
+
+ *piSizeVar += (uInt)size_extra_field;
+
+ return err;
+}
+
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile (file)
+ unzFile file;
+{
+ int err=UNZ_OK;
+ int Store;
+ uInt iSizeVar;
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ uLong offset_local_extrafield; /* offset of the local extra field */
+ uInt size_local_extrafield; /* size of the local extra field */
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_PARAMERROR;
+
+ if (s->pfile_in_zip_read != NULL)
+ unzCloseCurrentFile(file);
+
+ if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
+ &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+ return UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info = (file_in_zip_read_info_s*)
+ ALLOC(sizeof(file_in_zip_read_info_s));
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_INTERNALERROR;
+
+ pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+ pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+ pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+ pfile_in_zip_read_info->pos_local_extrafield=0;
+
+ if (pfile_in_zip_read_info->read_buffer==NULL)
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return UNZ_INTERNALERROR;
+ }
+
+ pfile_in_zip_read_info->stream_initialised=0;
+
+ if ((s->cur_file_info.compression_method!=0) &&
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+ Store = s->cur_file_info.compression_method==0;
+
+ pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+ pfile_in_zip_read_info->crc32=0;
+ pfile_in_zip_read_info->compression_method =
+ s->cur_file_info.compression_method;
+ pfile_in_zip_read_info->file=s->file;
+ pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+ pfile_in_zip_read_info->stream.total_out = 0;
+
+ if (!Store)
+ {
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+
+ err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=1;
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END.
+ * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+ * size of both compressed and uncompressed data
+ */
+ }
+ pfile_in_zip_read_info->rest_read_compressed =
+ s->cur_file_info.compressed_size ;
+ pfile_in_zip_read_info->rest_read_uncompressed =
+ s->cur_file_info.uncompressed_size ;
+
+
+ pfile_in_zip_read_info->pos_in_zipfile =
+ s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+ iSizeVar;
+
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+
+ s->pfile_in_zip_read = pfile_in_zip_read_info;
+ return UNZ_OK;
+}
+
+
+/*
+ Read bytes from the current file.
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile (file, buf, len)
+ unzFile file;
+ voidp buf;
+ unsigned len;
+{
+ int err=UNZ_OK;
+ uInt iRead = 0;
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->read_buffer == NULL))
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (len==0)
+ return 0;
+
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+ pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+
+ if (len>pfile_in_zip_read_info->rest_read_uncompressed)
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+ while (pfile_in_zip_read_info->stream.avail_out>0)
+ {
+ if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+ (pfile_in_zip_read_info->rest_read_compressed>0))
+ {
+ uInt uReadThis = UNZ_BUFSIZE;
+ if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+ uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+ if (uReadThis == 0)
+ return UNZ_EOF;
+ if (fseek(pfile_in_zip_read_info->file,
+ pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
+ return UNZ_ERRNO;
+ if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
+ pfile_in_zip_read_info->file)!=1)
+ return UNZ_ERRNO;
+ pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+ pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+
+ pfile_in_zip_read_info->stream.next_in =
+ (Bytef*)pfile_in_zip_read_info->read_buffer;
+ pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+ }
+
+ if (pfile_in_zip_read_info->compression_method==0)
+ {
+ uInt uDoCopy,i ;
+ if (pfile_in_zip_read_info->stream.avail_out <
+ pfile_in_zip_read_info->stream.avail_in)
+ uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+ else
+ uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+
+ for (i=0;i<uDoCopy;i++)
+ *(pfile_in_zip_read_info->stream.next_out+i) =
+ *(pfile_in_zip_read_info->stream.next_in+i);
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+ pfile_in_zip_read_info->stream.next_out,
+ uDoCopy);
+ pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+ pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+ pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+ pfile_in_zip_read_info->stream.next_out += uDoCopy;
+ pfile_in_zip_read_info->stream.next_in += uDoCopy;
+ pfile_in_zip_read_info->stream.total_out += uDoCopy;
+ iRead += uDoCopy;
+ }
+ else
+ {
+ uLong uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ uLong uOutThis;
+ int flush=Z_SYNC_FLUSH;
+
+ uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+ bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+ /*
+ if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+ pfile_in_zip_read_info->stream.avail_out) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ flush = Z_FINISH;
+ */
+ err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+ uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->crc32 =
+ crc32(pfile_in_zip_read_info->crc32,bufBefore,
+ (uInt)(uOutThis));
+
+ pfile_in_zip_read_info->rest_read_uncompressed -=
+ uOutThis;
+
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ if (err==Z_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=Z_OK)
+ break;
+ }
+ }
+
+ if (err==Z_OK)
+ return iRead;
+ return err;
+}
+
+
+/*
+ Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (file)
+ unzFile file;
+{
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+extern int ZEXPORT unzeof (file)
+ unzFile file;
+{
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field that can be read
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
+ unzFile file;
+ voidp buf;
+ unsigned len;
+{
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ uInt read_now;
+ uLong size_to_read;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
+ pfile_in_zip_read_info->pos_local_extrafield);
+
+ if (buf==NULL)
+ return (int)size_to_read;
+
+ if (len>size_to_read)
+ read_now = (uInt)size_to_read;
+ else
+ read_now = (uInt)len ;
+
+ if (read_now==0)
+ return 0;
+
+ if (fseek(pfile_in_zip_read_info->file,
+ pfile_in_zip_read_info->offset_local_extrafield +
+ pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
+ return UNZ_ERRNO;
+
+ return (int)read_now;
+}
+
+/*
+ Close the file in zip opened with unzipOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (file)
+ unzFile file;
+{
+ int err=UNZ_OK;
+
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+ {
+ if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+ err=UNZ_CRCERROR;
+ }
+
+
+ TRYFREE(pfile_in_zip_read_info->read_buffer);
+ pfile_in_zip_read_info->read_buffer = NULL;
+ if (pfile_in_zip_read_info->stream_initialised)
+ inflateEnd(&pfile_in_zip_read_info->stream);
+
+ pfile_in_zip_read_info->stream_initialised = 0;
+ TRYFREE(pfile_in_zip_read_info);
+
+ s->pfile_in_zip_read=NULL;
+
+ return err;
+}
+
+
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
+ unzFile file;
+ char *szComment;
+ uLong uSizeBuf;
+{
+ int err=UNZ_OK;
+ unz_s* s;
+ uLong uReadThis ;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+
+ uReadThis = uSizeBuf;
+ if (uReadThis>s->gi.size_comment)
+ uReadThis = s->gi.size_comment;
+
+ if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (uReadThis>0)
+ {
+ *szComment='\0';
+ if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)
+ return UNZ_ERRNO;
+ }
+
+ if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+ *(szComment+s->gi.size_comment)='\0';
+ return (int)uReadThis;
+}
--- /dev/null
+ unzOpen @61
+ unzClose @62
+ unzGetGlobalInfo @63
+ unzGetCurrentFileInfo @64
+ unzGoToFirstFile @65
+ unzGoToNextFile @66
+ unzOpenCurrentFile @67
+ unzReadCurrentFile @68
+ unztell @70
+ unzeof @71
+ unzCloseCurrentFile @72
+ unzGetGlobalComment @73
+ unzStringFileNameCompare @74
+ unzLocateFile @75
+ unzGetLocalExtrafield @76
--- /dev/null
+/* unzip.h -- IO for uncompress .zip files using zlib
+ Version 0.15 beta, Mar 19th, 1998,
+
+ Copyright (C) 1998 Gilles Vollant
+
+ This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
+ WinZip, InfoZip tools and compatible.
+ Encryption and multi volume ZipFile (span) are not supported.
+ Old compressions used by old PKZip 1.x are not supported
+
+ THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
+ CAN CHANGE IN FUTURE VERSION !!
+ I WAIT FEEDBACK at mail info@winimage.com
+ Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+/* for more info about .ZIP format, see
+ ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+ PkWare has also a specification at :
+ ftp://ftp.pkware.com/probdesc.zip */
+
+#ifndef _unz_H
+#define _unz_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (Z_ERRNO)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct unz_global_info_s
+{
+ uLong number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ uLong compressed_size; /* compressed size 4 bytes */
+ uLong uncompressed_size; /* uncompressed size 4 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity));
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
+ "zlib/zlib111.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+ unz_global_info *pglobal_info));
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+ char *szComment,
+ uLong uSizeBuf));
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file,
+ const char *szFileName,
+ int iCaseSensitivity));
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+ unz_file_info *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+/*
+ Get Info about the current file
+ if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+ the current file
+ if szFileName!=NULL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField!=NULL, the extra field information will be copied in extraField
+ (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment!=NULL, the comment string of the file will be copied in szComment
+ (commentBufferSize is the size of the buffer)
+*/
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+ from it, and close it (you can close it before reading all the file)
+ */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+/*
+ Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz_H */
--- /dev/null
+/* zip.c -- IO on .zip files using zlib
+ Version 0.15 beta, Mar 19th, 1998,
+
+ Read zip.h for more info
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "zip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#ifndef VERSIONMADEBY
+# define VERSIONMADEBY (0x0) /* platform depedent */
+#endif
+
+#ifndef Z_BUFSIZE
+#define Z_BUFSIZE (16384)
+#endif
+
+#ifndef Z_MAXFILENAMEINZIP
+#define Z_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+/*
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+*/
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+const char zip_copyright[] =
+ " zip 0.15 Copyright 1998 Gilles Vollant ";
+
+
+#define SIZEDATA_INDATABLOCK (4096-(4*4))
+
+#define LOCALHEADERMAGIC (0x04034b50)
+#define CENTRALHEADERMAGIC (0x02014b50)
+#define ENDHEADERMAGIC (0x06054b50)
+
+#define FLAG_LOCALHEADER_OFFSET (0x06)
+#define CRC_LOCALHEADER_OFFSET (0x0e)
+
+#define SIZECENTRALHEADER (0x2e) /* 46 */
+
+typedef struct linkedlist_datablock_internal_s
+{
+ struct linkedlist_datablock_internal_s* next_datablock;
+ uLong avail_in_this_block;
+ uLong filled_in_this_block;
+ uLong unused; /* for future use and alignement */
+ unsigned char data[SIZEDATA_INDATABLOCK];
+} linkedlist_datablock_internal;
+
+typedef struct linkedlist_data_s
+{
+ linkedlist_datablock_internal* first_block;
+ linkedlist_datablock_internal* last_block;
+} linkedlist_data;
+
+
+typedef struct
+{
+ z_stream stream; /* zLib stream structure for inflate */
+ int stream_initialised; /* 1 is stream is initialised */
+ uInt pos_in_buffered_data; /* last written byte in buffered_data */
+
+ uLong pos_local_header; /* offset of the local header of the file
+ currenty writing */
+ char* central_header; /* central header data for the current file */
+ uLong size_centralheader; /* size of the central header for cur file */
+ uLong flag; /* flag of the file currently writing */
+
+ int method; /* compression method of file currenty wr.*/
+ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
+ uLong dosDate;
+ uLong crc32;
+} curfile_info;
+
+typedef struct
+{
+ FILE * filezip;
+ linkedlist_data central_dir;/* datablock with central dir in construction*/
+ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
+ curfile_info ci; /* info on the file curretly writing */
+
+ uLong begin_pos; /* position of the beginning of the zipfile */
+ uLong number_entry;
+} zip_internal;
+
+local linkedlist_datablock_internal* allocate_new_datablock()
+{
+ linkedlist_datablock_internal* ldi;
+ ldi = (linkedlist_datablock_internal*)
+ ALLOC(sizeof(linkedlist_datablock_internal));
+ if (ldi!=NULL)
+ {
+ ldi->next_datablock = NULL ;
+ ldi->filled_in_this_block = 0 ;
+ ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
+ }
+ return ldi;
+}
+
+local void free_datablock(ldi)
+ linkedlist_datablock_internal* ldi;
+{
+ while (ldi!=NULL)
+ {
+ linkedlist_datablock_internal* ldinext = ldi->next_datablock;
+ TRYFREE(ldi);
+ ldi = ldinext;
+ }
+}
+
+local void init_linkedlist(ll)
+ linkedlist_data* ll;
+{
+ ll->first_block = ll->last_block = NULL;
+}
+
+local void free_linkedlist(ll)
+ linkedlist_data* ll;
+{
+ free_datablock(ll->first_block);
+ ll->first_block = ll->last_block = NULL;
+}
+
+
+local int add_data_in_datablock(ll,buf,len)
+ linkedlist_data* ll;
+ const void* buf;
+ uLong len;
+{
+ linkedlist_datablock_internal* ldi;
+ const unsigned char* from_copy;
+
+ if (ll==NULL)
+ return ZIP_INTERNALERROR;
+
+ if (ll->last_block == NULL)
+ {
+ ll->first_block = ll->last_block = allocate_new_datablock();
+ if (ll->first_block == NULL)
+ return ZIP_INTERNALERROR;
+ }
+
+ ldi = ll->last_block;
+ from_copy = (unsigned char*)buf;
+
+ while (len>0)
+ {
+ uInt copy_this;
+ uInt i;
+ unsigned char* to_copy;
+
+ if (ldi->avail_in_this_block==0)
+ {
+ ldi->next_datablock = allocate_new_datablock();
+ if (ldi->next_datablock == NULL)
+ return ZIP_INTERNALERROR;
+ ldi = ldi->next_datablock ;
+ ll->last_block = ldi;
+ }
+
+ if (ldi->avail_in_this_block < len)
+ copy_this = (uInt)ldi->avail_in_this_block;
+ else
+ copy_this = (uInt)len;
+
+ to_copy = &(ldi->data[ldi->filled_in_this_block]);
+
+ for (i=0;i<copy_this;i++)
+ *(to_copy+i)=*(from_copy+i);
+
+ ldi->filled_in_this_block += copy_this;
+ ldi->avail_in_this_block -= copy_this;
+ from_copy += copy_this ;
+ len -= copy_this;
+ }
+ return ZIP_OK;
+}
+
+
+local int write_datablock(fout,ll)
+ FILE * fout;
+ linkedlist_data* ll;
+{
+ linkedlist_datablock_internal* ldi;
+ ldi = ll->first_block;
+ while (ldi!=NULL)
+ {
+ if (ldi->filled_in_this_block > 0)
+ if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,1,fout)!=1)
+ return ZIP_ERRNO;
+ ldi = ldi->next_datablock;
+ }
+ return ZIP_OK;
+}
+
+/****************************************************************************/
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+ nbByte == 1, 2 or 4 (byte, short or long)
+*/
+
+local int ziplocal_putValue OF((FILE *file, uLong x, int nbByte));
+local int ziplocal_putValue (file, x, nbByte)
+ FILE *file;
+ uLong x;
+ int nbByte;
+{
+ unsigned char buf[4];
+ int n;
+ for (n = 0; n < nbByte; n++) {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+ if (fwrite(buf,nbByte,1,file)!=1)
+ return ZIP_ERRNO;
+ else
+ return ZIP_OK;
+}
+
+local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte));
+local void ziplocal_putValue_inmemory (dest, x, nbByte)
+ void* dest;
+ uLong x;
+ int nbByte;
+{
+ unsigned char* buf=(unsigned char*)dest;
+ int n;
+ for (n = 0; n < nbByte; n++) {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+}
+/****************************************************************************/
+
+
+local uLong ziplocal_TmzDateToDosDate(ptm,dosDate)
+ tm_zip* ptm;
+ uLong dosDate;
+{
+ uLong year = (uLong)ptm->tm_year;
+ if (year>1980)
+ year-=1980;
+ else if (year>80)
+ year-=80;
+ return
+ (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
+ ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
+}
+
+
+/****************************************************************************/
+
+extern zipFile ZEXPORT zipOpen (pathname, append)
+ const char *pathname;
+ int append;
+{
+ zip_internal ziinit;
+ zip_internal* zi;
+
+ ziinit.filezip = fopen(pathname,(append == 0) ? "wb" : "ab");
+ if (ziinit.filezip == NULL)
+ return NULL;
+ ziinit.begin_pos = ftell(ziinit.filezip);
+ ziinit.in_opened_file_inzip = 0;
+ ziinit.ci.stream_initialised = 0;
+ ziinit.number_entry = 0;
+ init_linkedlist(&(ziinit.central_dir));
+
+
+ zi = (zip_internal*)ALLOC(sizeof(zip_internal));
+ if (zi==NULL)
+ {
+ fclose(ziinit.filezip);
+ return NULL;
+ }
+
+ *zi = ziinit;
+ return (zipFile)zi;
+}
+
+extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level)
+ zipFile file;
+ const char* filename;
+ const zip_fileinfo* zipfi;
+ const void* extrafield_local;
+ uInt size_extrafield_local;
+ const void* extrafield_global;
+ uInt size_extrafield_global;
+ const char* comment;
+ int method;
+ int level;
+{
+ zip_internal* zi;
+ uInt size_filename;
+ uInt size_comment;
+ uInt i;
+ int err = ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ if ((method!=0) && (method!=Z_DEFLATED))
+ return ZIP_PARAMERROR;
+
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ if (err != ZIP_OK)
+ return err;
+ }
+
+
+ if (filename==NULL)
+ filename="-";
+
+ if (comment==NULL)
+ size_comment = 0;
+ else
+ size_comment = strlen(comment);
+
+ size_filename = strlen(filename);
+
+ if (zipfi == NULL)
+ zi->ci.dosDate = 0;
+ else
+ {
+ if (zipfi->dosDate != 0)
+ zi->ci.dosDate = zipfi->dosDate;
+ else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
+ }
+
+ zi->ci.flag = 0;
+ if ((level==8) || (level==9))
+ zi->ci.flag |= 2;
+ if ((level==2))
+ zi->ci.flag |= 4;
+ if ((level==1))
+ zi->ci.flag |= 6;
+
+ zi->ci.crc32 = 0;
+ zi->ci.method = method;
+ zi->ci.stream_initialised = 0;
+ zi->ci.pos_in_buffered_data = 0;
+ zi->ci.pos_local_header = ftell(zi->filezip);
+ zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename +
+ size_extrafield_global + size_comment;
+ zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader);
+
+ ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
+ /* version info */
+ ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
+ ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
+ ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
+
+ if (zipfi==NULL)
+ ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
+ else
+ ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
+
+ if (zipfi==NULL)
+ ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
+ else
+ ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
+
+ ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header,4);
+
+ for (i=0;i<size_filename;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
+
+ for (i=0;i<size_extrafield_global;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
+ *(((const char*)extrafield_global)+i);
+
+ for (i=0;i<size_comment;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
+ size_extrafield_global+i) = *(filename+i);
+ if (zi->ci.central_header == NULL)
+ return ZIP_INTERNALERROR;
+
+ /* write the local header */
+ err = ziplocal_putValue(zi->filezip,(uLong)LOCALHEADERMAGIC,4);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)20,2);/* version needed to extract */
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.flag,2);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.method,2);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.dosDate,4);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* crc 32, unknown */
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* compressed size, unknown */
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* uncompressed size, unknown */
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)size_filename,2);
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)size_extrafield_local,2);
+
+ if ((err==ZIP_OK) && (size_filename>0))
+ if (fwrite(filename,(uInt)size_filename,1,zi->filezip)!=1)
+ err = ZIP_ERRNO;
+
+ if ((err==ZIP_OK) && (size_extrafield_local>0))
+ if (fwrite(extrafield_local,(uInt)size_extrafield_local,1,zi->filezip)
+ !=1)
+ err = ZIP_ERRNO;
+
+ zi->ci.stream.avail_in = (uInt)0;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ zi->ci.stream.total_in = 0;
+ zi->ci.stream.total_out = 0;
+
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED))
+ {
+ zi->ci.stream.zalloc = (alloc_func)0;
+ zi->ci.stream.zfree = (free_func)0;
+ zi->ci.stream.opaque = (voidpf)0;
+
+ err = deflateInit2(&zi->ci.stream, level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
+
+ if (err==Z_OK)
+ zi->ci.stream_initialised = 1;
+ }
+
+
+ if (err==Z_OK)
+ zi->in_opened_file_inzip = 1;
+ return err;
+}
+
+extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
+ zipFile file;
+ const voidp buf;
+ unsigned len;
+{
+ zip_internal* zi;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+
+ zi->ci.stream.next_in = buf;
+ zi->ci.stream.avail_in = len;
+ zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
+
+ while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
+ {
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
+ !=1)
+ err = ZIP_ERRNO;
+ zi->ci.pos_in_buffered_data = 0;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+
+ if (zi->ci.method == Z_DEFLATED)
+ {
+ uLong uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_NO_FLUSH);
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+
+ }
+ else
+ {
+ uInt copy_this,i;
+ if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+ copy_this = zi->ci.stream.avail_in;
+ else
+ copy_this = zi->ci.stream.avail_out;
+ for (i=0;i<copy_this;i++)
+ *(((char*)zi->ci.stream.next_out)+i) =
+ *(((const char*)zi->ci.stream.next_in)+i);
+ {
+ zi->ci.stream.avail_in -= copy_this;
+ zi->ci.stream.avail_out-= copy_this;
+ zi->ci.stream.next_in+= copy_this;
+ zi->ci.stream.next_out+= copy_this;
+ zi->ci.stream.total_in+= copy_this;
+ zi->ci.stream.total_out+= copy_this;
+ zi->ci.pos_in_buffered_data += copy_this;
+ }
+ }
+ }
+
+ return 0;
+}
+
+extern int ZEXPORT zipCloseFileInZip (file)
+ zipFile file;
+{
+ zip_internal* zi;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+ zi->ci.stream.avail_in = 0;
+
+ if (zi->ci.method == Z_DEFLATED)
+ while (err==ZIP_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
+ !=1)
+ err = ZIP_ERRNO;
+ zi->ci.pos_in_buffered_data = 0;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_FINISH);
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+
+ if (err==Z_STREAM_END)
+ err=ZIP_OK; /* this is normal */
+
+ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
+ if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
+ !=1)
+ err = ZIP_ERRNO;
+
+ if ((zi->ci.method == Z_DEFLATED) && (err==ZIP_OK))
+ {
+ err=deflateEnd(&zi->ci.stream);
+ zi->ci.stream_initialised = 0;
+ }
+
+ ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)zi->ci.crc32,4); /*crc*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+20,
+ (uLong)zi->ci.stream.total_out,4); /*compr size*/
+ ziplocal_putValue_inmemory(zi->ci.central_header+24,
+ (uLong)zi->ci.stream.total_in,4); /*uncompr size*/
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
+ (uLong)zi->ci.size_centralheader);
+ free(zi->ci.central_header);
+
+ if (err==ZIP_OK)
+ {
+ long cur_pos_inzip = ftell(zi->filezip);
+ if (fseek(zi->filezip,
+ zi->ci.pos_local_header + 14,SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.crc32,4); /* crc 32, unknown */
+
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_out,4);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_in,4);
+
+ if (fseek(zi->filezip,
+ cur_pos_inzip,SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+ }
+
+ zi->number_entry ++;
+ zi->in_opened_file_inzip = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipClose (file, global_comment)
+ zipFile file;
+ const char* global_comment;
+{
+ zip_internal* zi;
+ int err = 0;
+ uLong size_centraldir = 0;
+ uLong centraldir_pos_inzip ;
+ uInt size_global_comment;
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ }
+
+ if (global_comment==NULL)
+ size_global_comment = 0;
+ else
+ size_global_comment = strlen(global_comment);
+
+
+ centraldir_pos_inzip = ftell(zi->filezip);
+ if (err==ZIP_OK)
+ {
+ linkedlist_datablock_internal* ldi = zi->central_dir.first_block ;
+ while (ldi!=NULL)
+ {
+ if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
+ if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,
+ 1,zi->filezip) !=1 )
+ err = ZIP_ERRNO;
+
+ size_centraldir += ldi->filled_in_this_block;
+ ldi = ldi->next_datablock;
+ }
+ }
+ free_datablock(zi->central_dir.first_block);
+
+ if (err==ZIP_OK) /* Magic End */
+ err = ziplocal_putValue(zi->filezip,(uLong)ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = ziplocal_putValue(zi->filezip,(uLong)0,2);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = ziplocal_putValue(zi->filezip,(uLong)0,2);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = ziplocal_putValue(zi->filezip,(uLong)size_centraldir,4);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the
+ starting disk number */
+ err = ziplocal_putValue(zi->filezip,(uLong)centraldir_pos_inzip ,4);
+
+ if (err==ZIP_OK) /* zipfile comment length */
+ err = ziplocal_putValue(zi->filezip,(uLong)size_global_comment,2);
+
+ if ((err==ZIP_OK) && (size_global_comment>0))
+ if (fwrite(global_comment,(uInt)size_global_comment,1,zi->filezip) !=1 )
+ err = ZIP_ERRNO;
+ fclose(zi->filezip);
+ TRYFREE(zi);
+
+ return err;
+}
--- /dev/null
+ zipOpen @80
+ zipOpenNewFileInZip @81
+ zipWriteInFileInZip @82
+ zipCloseFileInZip @83
+ zipClose @84
--- /dev/null
+/* zip.h -- IO for compress .zip files using zlib
+ Version 0.15 alpha, Mar 19th, 1998,
+
+ Copyright (C) 1998 Gilles Vollant
+
+ This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
+ WinZip, InfoZip tools and compatible.
+ Encryption and multi volume ZipFile (span) are not supported.
+ Old compressions used by old PKZip 1.x are not supported
+
+ For uncompress .zip file, look at unzip.h
+
+ THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
+ CAN CHANGE IN FUTURE VERSION !!
+ I WAIT FEEDBACK at mail info@winimage.com
+ Visit also http://www.winimage.com/zLibDll/zip.htm for evolution
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+
+/* for more info about .ZIP format, see
+ ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+ PkWare has also a specification at :
+ ftp://ftp.pkware.com/probdesc.zip
+*/
+
+#ifndef _zip_H
+#define _zip_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zipFile__;
+typedef zipFile__ *zipFile;
+#else
+typedef voidp zipFile;
+#endif
+
+#define ZIP_OK (0)
+#define ZIP_ERRNO (Z_ERRNO)
+#define ZIP_PARAMERROR (-102)
+#define ZIP_INTERNALERROR (-104)
+
+/* tm_zip contain date/time info */
+typedef struct tm_zip_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_zip;
+
+typedef struct
+{
+ tm_zip tmz_date; /* date in understandable format */
+ uLong dosDate; /* if dos_date == 0, tmu_date is used */
+/* uLong flag; */ /* general purpose bit flag 2 bytes */
+
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+} zip_fileinfo;
+
+extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));
+/*
+ Create a zipfile.
+ pathname contain on Windows NT a filename like "c:\\zlib\\zlib111.zip" or on
+ an Unix computer "zlib/zlib111.zip".
+ if the file pathname exist and append=1, the zip will be created at the end
+ of the file. (useful if the file contain a self extractor code)
+ If the zipfile cannot be opened, the return value is NULL.
+ Else, the return value is a zipFile Handle, usable with other function
+ of this zip package.
+
+
+*/
+
+extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level));
+/*
+ Open a file in the ZIP for writing.
+ filename : the filename in zip (if NULL, '-' without quote will be used
+ *zipfi contain supplemental information
+ if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
+ contains the extrafield data the the local header
+ if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+ contains the extrafield data the the local header
+ if comment != NULL, comment contain the comment string
+ method contain the compression method (0 for store, Z_DEFLATED for deflate)
+ level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
+*/
+
+extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
+ const voidp buf,
+ unsigned len));
+/*
+ Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+ Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipClose OF((zipFile file,
+ const char* global_comment));
+/*
+ Close the zipfile
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _zip_H */
--- /dev/null
+LIBRARY "zlib"
+
+DESCRIPTION '"""zlib data compression library"""'
+
+
+VERSION 1.11
+
+
+HEAPSIZE 1048576,8192
+
+EXPORTS
+ adler32 @1
+ compress @2
+ crc32 @3
+ deflate @4
+ deflateCopy @5
+ deflateEnd @6
+ deflateInit2_ @7
+ deflateInit_ @8
+ deflateParams @9
+ deflateReset @10
+ deflateSetDictionary @11
+ gzclose @12
+ gzdopen @13
+ gzerror @14
+ gzflush @15
+ gzopen @16
+ gzread @17
+ gzwrite @18
+ inflate @19
+ inflateEnd @20
+ inflateInit2_ @21
+ inflateInit_ @22
+ inflateReset @23
+ inflateSetDictionary @24
+ inflateSync @25
+ uncompress @26
+ zlibVersion @27
+ gzprintf @28
+ gzputc @29
+ gzgetc @30
+ gzseek @31
+ gzrewind @32
+ gztell @33
+ gzeof @34
+ gzsetparams @35
+ zError @36
+ inflateSyncPoint @37
+ get_crc_table @38
+ compress2 @39
+ gzputs @40
+ gzgets @41
+
+ unzOpen @61
+ unzClose @62
+ unzGetGlobalInfo @63
+ unzGetCurrentFileInfo @64
+ unzGoToFirstFile @65
+ unzGoToNextFile @66
+ unzOpenCurrentFile @67
+ unzReadCurrentFile @68
+ unztell @70
+ unzeof @71
+ unzCloseCurrentFile @72
+ unzGetGlobalComment @73
+ unzStringFileNameCompare @74
+ unzLocateFile @75
+ unzGetLocalExtrafield @76
+
+ zipOpen @80
+ zipOpenNewFileInZip @81
+ zipWriteInFileInZip @82
+ zipCloseFileInZip @83
+ zipClose @84
--- /dev/null
+# Microsoft Developer Studio Project File - Name="zlibvc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=zlibvc - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zlibvc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zlibvc.mak" CFG="zlibvc - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zlibvc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseAxp" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutAsm" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutCrtdll" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\zlib.dll"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc__"
+# PROP BASE Intermediate_Dir "zlibvc__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc__"
+# PROP Intermediate_Dir "zlibvc__"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:"zlibvc__\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_0"
+# PROP BASE Intermediate_Dir "zlibvc_0"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_0"
+# PROP Intermediate_Dir "zlibvc_0"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_0\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_1"
+# PROP BASE Intermediate_Dir "zlibvc_1"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_1"
+# PROP Intermediate_Dir "zlibvc_1"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_1\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "zlibvc - Win32 Release"
+# Name "zlibvc - Win32 Debug"
+# Name "zlibvc - Win32 ReleaseAxp"
+# Name "zlibvc - Win32 ReleaseWithoutAsm"
+# Name "zlibvc - Win32 ReleaseWithoutCrtdll"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\adler32.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ADLER=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_COMPR=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\crc32.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_CRC32=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_DEFLA=\
+ ".\deflate.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gvmat32c.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gzio.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_GZIO_=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFBL=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFCO=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inffast.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFFA=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inffast.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFLA=\
+ ".\infblock.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFTR=\
+ ".\inftrees.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFUT=\
+ ".\infblock.h"\
+ ".\infcodes.h"\
+ ".\inftrees.h"\
+ ".\infutil.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_TREES=\
+ ".\deflate.h"\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\uncompr.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_UNCOM=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\unzip.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zip.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlibvc.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.c
+
+!IF "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ZUTIL=\
+ ".\zconf.h"\
+ ".\zlib.h"\
+ ".\zutil.h"\
+
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zlibstat"=.\zlibstat.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zlibvc"=.\zlibvc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
--- /dev/null
+CC=cc
+CFLAGS=-g
+
+untgz: untgz.o ../../libz.a
+ $(CC) $(CFLAGS) -o untgz untgz.o -L../.. -lz
+
+untgz.o: untgz.c ../../zlib.h
+ $(CC) $(CFLAGS) -c -I../.. untgz.c
+
+../../libz.a:
+ cd ../..; make
+
+clean:
+ rm -f untgz untgz.o *~
--- /dev/null
+# Makefile for zlib. Modified for mingw32
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile,
+#
+# make -fmakefile.w32
+#
+
+CC=gcc
+
+# Generate dependencies (see end of the file)
+
+CPPFLAGS=-MMD
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is not found, replace with copy /Y .
+CP=cp -f
+
+# The default value of RM is "rm -f."
+# If "rm.exe" is not found, uncomment:
+# RM=del
+
+LD=gcc
+LDLIBS=-L. -lz
+LDFLAGS=-s
+
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o \
+ inffast.o
+
+TEST_OBJS = minigzip.o untgz.o
+
+all: minigzip.exe untgz.exe
+
+rebuild: clean all
+
+libz.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $(LDFLAGS) -o $@ $< $(LDLIBS)
+
+.PHONY : clean
+
+clean:
+ $(RM) *.d *.o *.exe libz.a foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
+
--- /dev/null
+/*
+ * untgz.c -- Display contents and/or extract file from
+ * a gzip'd TAR file
+ * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef unix
+# include <unistd.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "zlib.h"
+
+#ifdef WIN32
+# ifndef F_OK
+# define F_OK (0)
+# endif
+# ifdef _MSC_VER
+# define mkdir(dirname,mode) _mkdir(dirname)
+# define strdup(str) _strdup(str)
+# define unlink(fn) _unlink(fn)
+# define access(path,mode) _access(path,mode)
+# else
+# define mkdir(dirname,mode) _mkdir(dirname)
+# endif
+#else
+# include <utime.h>
+#endif
+
+
+/* Values used in typeflag field. */
+
+#define REGTYPE '0' /* regular file */
+#define AREGTYPE '\0' /* regular file */
+#define LNKTYPE '1' /* link */
+#define SYMTYPE '2' /* reserved */
+#define CHRTYPE '3' /* character special */
+#define BLKTYPE '4' /* block special */
+#define DIRTYPE '5' /* directory */
+#define FIFOTYPE '6' /* FIFO special */
+#define CONTTYPE '7' /* reserved */
+
+#define BLOCKSIZE 512
+
+struct tar_header
+{ /* byte offset */
+ char name[100]; /* 0 */
+ char mode[8]; /* 100 */
+ char uid[8]; /* 108 */
+ char gid[8]; /* 116 */
+ char size[12]; /* 124 */
+ char mtime[12]; /* 136 */
+ char chksum[8]; /* 148 */
+ char typeflag; /* 156 */
+ char linkname[100]; /* 157 */
+ char magic[6]; /* 257 */
+ char version[2]; /* 263 */
+ char uname[32]; /* 265 */
+ char gname[32]; /* 297 */
+ char devmajor[8]; /* 329 */
+ char devminor[8]; /* 337 */
+ char prefix[155]; /* 345 */
+ /* 500 */
+};
+
+union tar_buffer {
+ char buffer[BLOCKSIZE];
+ struct tar_header header;
+};
+
+enum { TGZ_EXTRACT = 0, TGZ_LIST };
+
+static char *TGZfname OF((const char *));
+void TGZnotfound OF((const char *));
+
+int getoct OF((char *, int));
+char *strtime OF((time_t *));
+int ExprMatch OF((char *,char *));
+
+int makedir OF((char *));
+int matchname OF((int,int,char **,char *));
+
+void error OF((const char *));
+int tar OF((gzFile, int, int, int, char **));
+
+void help OF((int));
+int main OF((int, char **));
+
+char *prog;
+
+/* This will give a benign warning */
+
+static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar", NULL };
+
+/* Return the real name of the TGZ archive */
+/* or NULL if it does not exist. */
+
+static char *TGZfname OF((const char *fname))
+{
+ static char buffer[1024];
+ int origlen,i;
+
+ strcpy(buffer,fname);
+ origlen = strlen(buffer);
+
+ for (i=0; TGZprefix[i]; i++)
+ {
+ strcpy(buffer+origlen,TGZprefix[i]);
+ if (access(buffer,F_OK) == 0)
+ return buffer;
+ }
+ return NULL;
+}
+
+/* error message for the filename */
+
+void TGZnotfound OF((const char *fname))
+{
+ int i;
+
+ fprintf(stderr,"%s : couldn't find ",prog);
+ for (i=0;TGZprefix[i];i++)
+ fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
+ fname,
+ TGZprefix[i]);
+ exit(1);
+}
+
+
+/* help functions */
+
+int getoct(char *p,int width)
+{
+ int result = 0;
+ char c;
+
+ while (width --)
+ {
+ c = *p++;
+ if (c == ' ')
+ continue;
+ if (c == 0)
+ break;
+ result = result * 8 + (c - '0');
+ }
+ return result;
+}
+
+char *strtime (time_t *t)
+{
+ struct tm *local;
+ static char result[32];
+
+ local = localtime(t);
+ sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
+ local->tm_mday, local->tm_mon+1, local->tm_year+1900,
+ local->tm_hour, local->tm_min, local->tm_sec);
+ return result;
+}
+
+
+/* regular expression matching */
+
+#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
+
+int ExprMatch(char *string,char *expr)
+{
+ while (1)
+ {
+ if (ISSPECIAL(*expr))
+ {
+ if (*expr == '/')
+ {
+ if (*string != '\\' && *string != '/')
+ return 0;
+ string ++; expr++;
+ }
+ else if (*expr == '*')
+ {
+ if (*expr ++ == 0)
+ return 1;
+ while (*++string != *expr)
+ if (*string == 0)
+ return 0;
+ }
+ }
+ else
+ {
+ if (*string != *expr)
+ return 0;
+ if (*expr++ == 0)
+ return 1;
+ string++;
+ }
+ }
+}
+
+/* recursive make directory */
+/* abort if you get an ENOENT errno somewhere in the middle */
+/* e.g. ignore error "mkdir on existing directory" */
+/* */
+/* return 1 if OK */
+/* 0 on error */
+
+int makedir (char *newdir)
+{
+ char *buffer = strdup(newdir);
+ char *p;
+ int len = strlen(buffer);
+
+ if (len <= 0) {
+ free(buffer);
+ return 0;
+ }
+ if (buffer[len-1] == '/') {
+ buffer[len-1] = '\0';
+ }
+ if (mkdir(buffer, 0775) == 0)
+ {
+ free(buffer);
+ return 1;
+ }
+
+ p = buffer+1;
+ while (1)
+ {
+ char hold;
+
+ while(*p && *p != '\\' && *p != '/')
+ p++;
+ hold = *p;
+ *p = 0;
+ if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
+ {
+ fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
+ free(buffer);
+ return 0;
+ }
+ if (hold == 0)
+ break;
+ *p++ = hold;
+ }
+ free(buffer);
+ return 1;
+}
+
+int matchname (int arg,int argc,char **argv,char *fname)
+{
+ if (arg == argc) /* no arguments given (untgz tgzarchive) */
+ return 1;
+
+ while (arg < argc)
+ if (ExprMatch(fname,argv[arg++]))
+ return 1;
+
+ return 0; /* ignore this for the moment being */
+}
+
+
+/* Tar file list or extract */
+
+int tar (gzFile in,int action,int arg,int argc,char **argv)
+{
+ union tar_buffer buffer;
+ int len;
+ int err;
+ int getheader = 1;
+ int remaining = 0;
+ FILE *outfile = NULL;
+ char fname[BLOCKSIZE];
+ time_t tartime;
+
+ if (action == TGZ_LIST)
+ printf(" day time size file\n"
+ " ---------- -------- --------- -------------------------------------\n");
+ while (1)
+ {
+ len = gzread(in, &buffer, BLOCKSIZE);
+ if (len < 0)
+ error (gzerror(in, &err));
+ /*
+ * Always expect complete blocks to process
+ * the tar information.
+ */
+ if (len != BLOCKSIZE)
+ error("gzread: incomplete block read");
+
+ /*
+ * If we have to get a tar header
+ */
+ if (getheader == 1)
+ {
+ /*
+ * if we met the end of the tar
+ * or the end-of-tar block,
+ * we are done
+ */
+ if ((len == 0) || (buffer.header.name[0]== 0)) break;
+
+ tartime = (time_t)getoct(buffer.header.mtime,12);
+ strcpy(fname,buffer.header.name);
+
+ switch (buffer.header.typeflag)
+ {
+ case DIRTYPE:
+ if (action == TGZ_LIST)
+ printf(" %s <dir> %s\n",strtime(&tartime),fname);
+ if (action == TGZ_EXTRACT)
+ makedir(fname);
+ break;
+ case REGTYPE:
+ case AREGTYPE:
+ remaining = getoct(buffer.header.size,12);
+ if (action == TGZ_LIST)
+ printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
+ if (action == TGZ_EXTRACT)
+ {
+ if ((remaining) && (matchname(arg,argc,argv,fname)))
+ {
+ outfile = fopen(fname,"wb");
+ if (outfile == NULL) {
+ /* try creating directory */
+ char *p = strrchr(fname, '/');
+ if (p != NULL) {
+ *p = '\0';
+ makedir(fname);
+ *p = '/';
+ outfile = fopen(fname,"wb");
+ }
+ }
+ fprintf(stderr,
+ "%s %s\n",
+ (outfile) ? "Extracting" : "Couldn't create",
+ fname);
+ }
+ else
+ outfile = NULL;
+ }
+ /*
+ * could have no contents
+ */
+ getheader = (remaining) ? 0 : 1;
+ break;
+ default:
+ if (action == TGZ_LIST)
+ printf(" %s <---> %s\n",strtime(&tartime),fname);
+ break;
+ }
+ }
+ else
+ {
+ unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
+
+ if ((action == TGZ_EXTRACT) && (outfile != NULL))
+ {
+ if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
+ {
+ fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
+ fclose(outfile);
+ unlink(fname);
+ }
+ }
+ remaining -= bytes;
+ if (remaining == 0)
+ {
+ getheader = 1;
+ if ((action == TGZ_EXTRACT) && (outfile != NULL))
+ {
+#ifdef WIN32
+ HANDLE hFile;
+ FILETIME ftm,ftLocal;
+ SYSTEMTIME st;
+ struct tm localt;
+
+ fclose(outfile);
+
+ localt = *localtime(&tartime);
+
+ hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ st.wYear = (WORD)localt.tm_year+1900;
+ st.wMonth = (WORD)localt.tm_mon;
+ st.wDayOfWeek = (WORD)localt.tm_wday;
+ st.wDay = (WORD)localt.tm_mday;
+ st.wHour = (WORD)localt.tm_hour;
+ st.wMinute = (WORD)localt.tm_min;
+ st.wSecond = (WORD)localt.tm_sec;
+ st.wMilliseconds = 0;
+ SystemTimeToFileTime(&st,&ftLocal);
+ LocalFileTimeToFileTime(&ftLocal,&ftm);
+ SetFileTime(hFile,&ftm,NULL,&ftm);
+ CloseHandle(hFile);
+
+ outfile = NULL;
+#else
+ struct utimbuf settime;
+
+ settime.actime = settime.modtime = tartime;
+
+ fclose(outfile);
+ outfile = NULL;
+ utime(fname,&settime);
+#endif
+ }
+ }
+ }
+ }
+
+ if (gzclose(in) != Z_OK)
+ error("failed gzclose");
+
+ return 0;
+}
+
+
+/* =========================================================== */
+
+void help(int exitval)
+{
+ fprintf(stderr,
+ "untgz v 0.1\n"
+ " an sample application of zlib 1.0.4\n\n"
+ "Usage : untgz TGZfile to extract all files\n"
+ " untgz TGZfile fname ... to extract selected files\n"
+ " untgz -l TGZfile to list archive contents\n"
+ " untgz -h to display this help\n\n");
+ exit(exitval);
+}
+
+void error(const char *msg)
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+
+/* ====================================================================== */
+
+int _CRT_glob = 0; /* disable globbing of the arguments */
+
+int main(int argc,char **argv)
+{
+ int action = TGZ_EXTRACT;
+ int arg = 1;
+ char *TGZfile;
+ gzFile *f;
+
+
+ prog = strrchr(argv[0],'\\');
+ if (prog == NULL)
+ {
+ prog = strrchr(argv[0],'/');
+ if (prog == NULL)
+ {
+ prog = strrchr(argv[0],':');
+ if (prog == NULL)
+ prog = argv[0];
+ else
+ prog++;
+ }
+ else
+ prog++;
+ }
+ else
+ prog++;
+
+ if (argc == 1)
+ help(0);
+
+ if (strcmp(argv[arg],"-l") == 0)
+ {
+ action = TGZ_LIST;
+ if (argc == ++arg)
+ help(0);
+ }
+ else if (strcmp(argv[arg],"-h") == 0)
+ {
+ help(0);
+ }
+
+ if ((TGZfile = TGZfname(argv[arg])) == NULL)
+ TGZnotfound(argv[arg]);
+
+ ++arg;
+ if ((action == TGZ_LIST) && (arg != argc))
+ help(1);
+
+/*
+ * Process the TGZ file
+ */
+ switch(action)
+ {
+ case TGZ_LIST:
+ case TGZ_EXTRACT:
+ f = gzopen(TGZfile,"rb");
+ if (f == NULL)
+ {
+ fprintf(stderr,"%s: Couldn't gzopen %s\n",
+ prog,
+ TGZfile);
+ return 1;
+ }
+ exit(tar(f, action, arg, argc, argv));
+ break;
+
+ default:
+ error("Unknown option!");
+ exit(1);
+ }
+
+ return 0;
+}
--- /dev/null
+See below some functions declarations for Visual Basic.
+
+Frequently Asked Question:
+
+Q: Each time I use the compress function I get the -5 error (not enough
+ room in the output buffer).
+
+A: Make sure that the length of the compressed buffer is passed by
+ reference ("as any"), not by value ("as long"). Also check that
+ before the call of compress this length is equal to the total size of
+ the compressed buffer and not zero.
+
+
+From: "Jon Caruana" <jon-net@usa.net>
+Subject: Re: How to port zlib declares to vb?
+Date: Mon, 28 Oct 1996 18:33:03 -0600
+
+Got the answer! (I haven't had time to check this but it's what I got, and
+looks correct):
+
+He has the following routines working:
+ compress
+ uncompress
+ gzopen
+ gzwrite
+ gzread
+ gzclose
+
+Declares follow: (Quoted from Carlos Rios <c_rios@sonda.cl>, in Vb4 form)
+
+#If Win16 Then 'Use Win16 calls.
+Declare Function compress Lib "ZLIB.DLL" (ByVal compr As
+ String, comprLen As Any, ByVal buf As String, ByVal buflen
+ As Long) As Integer
+Declare Function uncompress Lib "ZLIB.DLL" (ByVal uncompr
+ As String, uncomprLen As Any, ByVal compr As String, ByVal
+ lcompr As Long) As Integer
+Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As
+ String, ByVal mode As String) As Long
+Declare Function gzread Lib "ZLIB.DLL" (ByVal file As
+ Long, ByVal uncompr As String, ByVal uncomprLen As Integer)
+ As Integer
+Declare Function gzwrite Lib "ZLIB.DLL" (ByVal file As
+ Long, ByVal uncompr As String, ByVal uncomprLen As Integer)
+ As Integer
+Declare Function gzclose Lib "ZLIB.DLL" (ByVal file As
+ Long) As Integer
+#Else
+Declare Function compress Lib "ZLIB32.DLL"
+ (ByVal compr As String, comprLen As Any, ByVal buf As
+ String, ByVal buflen As Long) As Integer
+Declare Function uncompress Lib "ZLIB32.DLL"
+ (ByVal uncompr As String, uncomprLen As Any, ByVal compr As
+ String, ByVal lcompr As Long) As Long
+Declare Function gzopen Lib "ZLIB32.DLL"
+ (ByVal file As String, ByVal mode As String) As Long
+Declare Function gzread Lib "ZLIB32.DLL"
+ (ByVal file As Long, ByVal uncompr As String, ByVal
+ uncomprLen As Long) As Long
+Declare Function gzwrite Lib "ZLIB32.DLL"
+ (ByVal file As Long, ByVal uncompr As String, ByVal
+ uncomprLen As Long) As Long
+Declare Function gzclose Lib "ZLIB32.DLL"
+ (ByVal file As Long) As Long
+#End If
+
+-Jon Caruana
+jon-net@usa.net
+Microsoft Sitebuilder Network Level 1 Member - HTML Writer's Guild Member
--- /dev/null
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+#define local static
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+ Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The table is simply the CRC of all possible eight bit values. This is all
+ the information needed to generate CRC's on data a byte at a time for all
+ combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+ uLong c;
+ int n, k;
+ uLong poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* make exclusive-or pattern from polynomial (0xedb88320L) */
+ poly = 0L;
+ for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+ poly |= 1L << (31 - p[n]);
+
+ for (n = 0; n < 256; n++)
+ {
+ c = (uLong)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[n] = c;
+ }
+ crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+#endif
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty) make_crc_table();
+#endif
+ return (const uLongf *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+ uLong crc;
+ const Bytef *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif
+ crc = crc ^ 0xffffffffL;
+ while (len >= 8)
+ {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+ return crc ^ 0xffffffffL;
+}
--- /dev/null
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.1.3 Copyright 1995-1998 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+local block_state deflate_slow OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int noheader = 0;
+ static const char* my_version = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == Z_NULL) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#ifdef FASTEST
+ level = 1;
+#endif
+
+ if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->noheader = noheader;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->status != INIT_STATE) return Z_STREAM_ERROR;
+
+ s = strm->state;
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->noheader < 0) {
+ s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+ }
+ s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+ strm->adler = 1;
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+ if (level == Z_DEFAULT_COMPRESSION) {
+ level = 6;
+ }
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the zlib header */
+ if (s->status == INIT_STATE) {
+
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags = (s->level-1) >> 1;
+
+ if (level_flags > 3) level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = 1L;
+ }
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->noheader) return Z_STREAM_END;
+
+ /* Write the zlib trailer (adler32) */
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ s->noheader = -1; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE && status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ *dest = *source;
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ *ds = *ss;
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (!strm->state->noheader) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+#ifndef FASTEST
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+
+#else /* FASTEST */
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return len <= s->lookahead ? len : s->lookahead;
+}
+#endif /* FASTEST */
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in hash table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+ (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR))) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
--- /dev/null
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1998 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+#include "zutil.h"
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ int pending; /* nb of bytes in the pending buffer */
+ int noheader; /* suppress zlib header and adler32 */
+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif
--- /dev/null
+# descrip.mms: MMS description file for building zlib on VMS
+# written by Martin P.J. Zinser <m.zinser@gsi.de>
+
+cc_defs =
+c_deb =
+
+.ifdef __DECC__
+pref = /prefix=all
+.endif
+
+OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\
+ deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\
+ inftrees.obj, infcodes.obj, infutil.obj, inffast.obj
+
+CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF)
+
+all : example.exe minigzip.exe
+ @ write sys$output " Example applications available"
+libz.olb : libz.olb($(OBJS))
+ @ write sys$output " libz available"
+
+example.exe : example.obj libz.olb
+ link example,libz.olb/lib
+
+minigzip.exe : minigzip.obj libz.olb
+ link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib
+
+clean :
+ delete *.obj;*,libz.olb;*
+
+
+# Other dependencies.
+adler32.obj : zutil.h zlib.h zconf.h
+compress.obj : zlib.h zconf.h
+crc32.obj : zutil.h zlib.h zconf.h
+deflate.obj : deflate.h zutil.h zlib.h zconf.h
+example.obj : zlib.h zconf.h
+gzio.obj : zutil.h zlib.h zconf.h
+infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.obj : zutil.h zlib.h zconf.h infblock.h
+inftrees.obj : zutil.h zlib.h zconf.h inftrees.h
+infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.obj : zlib.h zconf.h
+trees.obj : deflate.h zutil.h zlib.h zconf.h
+uncompr.obj : zlib.h zconf.h
+zutil.obj : zutil.h zlib.h zconf.h
--- /dev/null
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#else
+ extern void exit OF((int));
+#endif
+
+#if defined(VMS) || defined(RISCOS)
+# define TESTFILE "foo-gz"
+#else
+# define TESTFILE "foo.gz"
+#endif
+
+#define CHECK_ERR(err, msg) { \
+ if (err != Z_OK) { \
+ fprintf(stderr, "%s error: %d\n", msg, err); \
+ exit(1); \
+ } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_gzio OF((const char *out, const char *in,
+ Byte *uncompr, int uncomprLen));
+void test_deflate OF((Byte *compr, uLong comprLen));
+void test_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_flush OF((Byte *compr, uLong *comprLen));
+void test_sync OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate OF((Byte *compr, uLong comprLen));
+void test_dict_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ uLong len = strlen(hello)+1;
+
+ err = compress(compr, &comprLen, (const Bytef*)hello, len);
+ CHECK_ERR(err, "compress");
+
+ strcpy((char*)uncompr, "garbage");
+
+ err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+ CHECK_ERR(err, "uncompress");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad uncompress\n");
+ exit(1);
+ } else {
+ printf("uncompress(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(out, in, uncompr, uncomprLen)
+ const char *out; /* compressed output file */
+ const char *in; /* compressed input file */
+ Byte *uncompr;
+ int uncomprLen;
+{
+ int err;
+ int len = strlen(hello)+1;
+ gzFile file;
+ z_off_t pos;
+
+ file = gzopen(out, "wb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ gzputc(file, 'h');
+ if (gzputs(file, "ello") != 4) {
+ fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (gzprintf(file, ", %s!", "hello") != 8) {
+ fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
+ gzclose(file);
+
+ file = gzopen(in, "rb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ }
+ strcpy((char*)uncompr, "garbage");
+
+ uncomprLen = gzread(file, uncompr, (unsigned)uncomprLen);
+ if (uncomprLen != len) {
+ fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
+ exit(1);
+ } else {
+ printf("gzread(): %s\n", (char *)uncompr);
+ }
+
+ pos = gzseek(file, -8L, SEEK_CUR);
+ if (pos != 6 || gztell(file) != pos) {
+ fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+ (long)pos, (long)gztell(file));
+ exit(1);
+ }
+
+ if (gzgetc(file) != ' ') {
+ fprintf(stderr, "gzgetc error\n");
+ exit(1);
+ }
+
+ gzgets(file, (char*)uncompr, uncomprLen);
+ uncomprLen = strlen((char*)uncompr);
+ if (uncomprLen != 6) { /* "hello!" */
+ fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello+7)) {
+ fprintf(stderr, "bad gzgets after gzseek\n");
+ exit(1);
+ } else {
+ printf("gzgets() after gzseek: %s\n", (char *)uncompr);
+ }
+
+ gzclose(file);
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ int len = strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+
+ while (c_stream.total_in != (uLong)len && c_stream.total_out < comprLen) {
+ c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ }
+ /* Finish the stream, still forcing small buffers: */
+ for (;;) {
+ c_stream.avail_out = 1;
+ err = deflate(&c_stream, Z_FINISH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "deflate");
+ }
+
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 0;
+ d_stream.next_out = uncompr;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+ d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate\n");
+ exit(1);
+ } else {
+ printf("inflate(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_SPEED);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ /* At this point, uncompr is still mostly zeroes, so it should compress
+ * very well:
+ */
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ if (c_stream.avail_in != 0) {
+ fprintf(stderr, "deflate not greedy\n");
+ exit(1);
+ }
+
+ /* Feed in already compressed data and switch to no compression: */
+ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+ c_stream.next_in = compr;
+ c_stream.avail_in = (uInt)comprLen/2;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ /* Switch back to compressing mode: */
+ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ for (;;) {
+ d_stream.next_out = uncompr; /* discard the output */
+ d_stream.avail_out = (uInt)uncomprLen;
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "large inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+ fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+ exit(1);
+ } else {
+ printf("large_inflate(): OK\n");
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+ Byte *compr;
+ uLong *comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ int len = strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+ c_stream.avail_in = 3;
+ c_stream.avail_out = (uInt)*comprLen;
+ err = deflate(&c_stream, Z_FULL_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ compr[3]++; /* force an error in first compressed block */
+ c_stream.avail_in = len - 3;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ CHECK_ERR(err, "deflate");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+
+ *comprLen = c_stream.total_out;
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 2; /* just read the zlib header */
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ inflate(&d_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "inflate");
+
+ d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
+ err = inflateSync(&d_stream); /* but skip the damaged part */
+ CHECK_ERR(err, "inflateSync");
+
+ err = inflate(&d_stream, Z_FINISH);
+ if (err != Z_DATA_ERROR) {
+ fprintf(stderr, "inflate should report DATA_ERROR\n");
+ /* Because of incorrect adler32 */
+ exit(1);
+ }
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ printf("after inflateSync(): hel%s\n", (char *)uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ err = deflateSetDictionary(&c_stream,
+ (const Bytef*)dictionary, sizeof(dictionary));
+ CHECK_ERR(err, "deflateSetDictionary");
+
+ dictId = c_stream.adler;
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.avail_in = (uInt)strlen(hello)+1;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ for (;;) {
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ if (err == Z_NEED_DICT) {
+ if (d_stream.adler != dictId) {
+ fprintf(stderr, "unexpected dictionary");
+ exit(1);
+ }
+ err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+ sizeof(dictionary));
+ }
+ CHECK_ERR(err, "inflate with dict");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate with dict\n");
+ exit(1);
+ } else {
+ printf("inflate with dictionary: %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Usage: example [output.gz [input.gz]]
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ Byte *compr, *uncompr;
+ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+ uLong uncomprLen = comprLen;
+ static const char* myVersion = ZLIB_VERSION;
+
+ if (zlibVersion()[0] != myVersion[0]) {
+ fprintf(stderr, "incompatible zlib version\n");
+ exit(1);
+
+ } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+ fprintf(stderr, "warning: different zlib version\n");
+ }
+
+ compr = (Byte*)calloc((uInt)comprLen, 1);
+ uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
+ /* compr and uncompr are cleared to avoid reading uninitialized
+ * data and to ensure that uncompr compresses well.
+ */
+ if (compr == Z_NULL || uncompr == Z_NULL) {
+ printf("out of memory\n");
+ exit(1);
+ }
+ test_compress(compr, comprLen, uncompr, uncomprLen);
+
+ test_gzio((argc > 1 ? argv[1] : TESTFILE),
+ (argc > 2 ? argv[2] : TESTFILE),
+ uncompr, (int)uncomprLen);
+
+ test_deflate(compr, comprLen);
+ test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+ test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_flush(compr, &comprLen);
+ test_sync(compr, comprLen, uncompr, uncomprLen);
+ comprLen = uncomprLen;
+
+ test_dict_deflate(compr, comprLen);
+ test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ exit(0);
+ return 0; /* to avoid warning */
+}
--- /dev/null
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_DEFLATE to avoid the compression code.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ long startpos; /* start of compressed data in file (header skipped) */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open return NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->startpos = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * startpos anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->startpos = (ftell(s->file) - s->stream.avail_in);
+ }
+
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[20];
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Check the gzip magic header */
+ for (len = 0; len < 2; len++) {
+ c = get_byte(s);
+ if (c != gz_magic[len]) {
+ if (len != 0) s->stream.avail_in++, s->stream.next_in--;
+ if (c != EOF) {
+ s->stream.avail_in++, s->stream.next_in--;
+ s->transparent = 1;
+ }
+ s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
+ return;
+ }
+ }
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
+ s->file);
+ }
+ len -= s->stream.avail_out;
+ s->stream.total_in += (uLong)len;
+ s->stream.total_out += (uLong)len;
+ if (len == 0) s->z_eof = 1;
+ return (int)len;
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may
+ * be different from s->stream.total_out) in case of
+ * concatenated .gz files. Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ uLong total_in = s->stream.total_in;
+ uLong total_out = s->stream.total_out;
+
+ inflateReset(&(s->stream));
+ s->stream.total_in = total_in;
+ s->stream.total_out = total_out;
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_DEFLATE
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ const voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ va_start(va, format);
+#ifdef HAS_vsnprintf
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+#else
+ (void)vsprintf(buf, format, va);
+#endif
+ va_end(va);
+ len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
+ if (len <= 0) return 0;
+
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+#ifdef HAS_snprintf
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#else
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#endif
+ len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
+ if (len <= 0) return 0;
+
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->z_err = deflate(&(s->stream), flush);
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_DEFLATE */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->stream.total_in;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return (z_off_t)s->stream.total_in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->stream.total_out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->stream.total_in = s->stream.total_out = (uLong)offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if ((uLong)offset >= s->stream.total_out) {
+ offset -= s->stream.total_out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return (z_off_t)s->stream.total_out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+
+ if (s->startpos == 0) { /* not a compressed file */
+ rewind(s->file);
+ return 0;
+ }
+
+ (void) inflateReset(&s->stream);
+ return fseek(s->file, s->startpos, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ int err;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ return Z_STREAM_ERROR;
+#else
+ err = do_flush (file, Z_FINISH);
+ if (err != Z_OK) return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, s->stream.total_in);
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+/* ===========================================================================
+ Returns the error message for the last error which occured on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occured in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char* ZEXPORT gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
--- /dev/null
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ if (c != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens);
+ if (s->mode == CODES)
+ inflate_codes_free(s->sub.decode.codes, z);
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+ Tracev((stderr, "inflate: blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->hufts =
+ (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+ {
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Tracev((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, Z_NULL);
+ return s;
+}
+
+
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Tracev((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BAD;
+ z->msg = (char*)"invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = BAD;
+ z->msg = (char*)"invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BAD;
+ z->msg = (char*)"too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, s->hufts, z);
+ if (t != Z_OK)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ r = t;
+ if (r == Z_DATA_ERROR)
+ s->mode = BAD;
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->bits;
+ c = h->base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ z->msg = (char*)"invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td,
+ s->hufts, z);
+ ZFREE(z, s->sub.trees.blens);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ s->mode = BAD;
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.codes = c;
+ }
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONE;
+ case DONE:
+ r = Z_STREAM_END;
+ LEAVE
+ case BAD:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_blocks_reset(s, z, Z_NULL);
+ ZFREE(z, s->window);
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ Tracev((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt n;
+{
+ zmemcpy(s->window, d, n);
+ s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH.
+ * IN assertion: s != Z_NULL
+ */
+int inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+ return s->mode == LENS;
+}
--- /dev/null
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+ z_streamp z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+extern int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int)); /* initial return code */
+
+extern void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+extern int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_streamp));
+
+extern void inflate_set_dictionary OF((
+ inflate_blocks_statef *s,
+ const Bytef *d, /* dictionary */
+ uInt n)); /* dictionary length */
+
+extern int inflate_blocks_sync_point OF((
+ inflate_blocks_statef *s));
--- /dev/null
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ inflate_codes_mode mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
+ s->end - (c->sub.copy.dist - (q - s->window)) :
+ q - c->sub.copy.dist;
+#else
+ f = q - c->sub.copy.dist;
+ if ((uInt)(q - s->window) < c->sub.copy.dist)
+ f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+ ZFREE(z, c);
+ Tracev((stderr, "inflate: codes free\n"));
+}
--- /dev/null
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_streamp ));
+
+extern int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+extern void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_streamp ));
+
--- /dev/null
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ if ((uInt)(q - s->window) >= d) /* offset before dest */
+ { /* just copy */
+ r = q - d;
+ *q++ = *r++; c--; /* minimum count is three, */
+ *q++ = *r++; c--; /* so unroll loop a little */
+ }
+ else /* else offset after destination */
+ {
+ e = d - (uInt)(q - s->window); /* bytes from offset to end */
+ r = s->end - e; /* pointer to offset */
+ if (c > e) /* if source crosses, */
+ {
+ c -= e; /* copy to end of window */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window; /* copy rest from start of window */
+ }
+ }
+ do { /* copy all or what's left */
+ *q++ = *r++;
+ } while (--c);
+ break;
+ }
+ else if ((e & 64) == 0)
+ {
+ t += t->base;
+ e = (t += ((uInt)b & inflate_mask[e]))->exop;
+ }
+ else
+ {
+ z->msg = (char*)"invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ t += t->base;
+ if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = (char*)"invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
--- /dev/null
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_streamp ));
--- /dev/null
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+ };
+local inflate_huft fixed_td[] = {
+ {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+ {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+ {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+ {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+ {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+ {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+ {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+ {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+ };
--- /dev/null
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+typedef enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ DICT4, /* four dictionary check bytes to go */
+ DICT3, /* three dictionary check bytes to go */
+ DICT2, /* two dictionary check bytes to go */
+ DICT1, /* one dictionary check byte to go */
+ DICT0, /* waiting for inflateSetDictionary */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ inflate_mode mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z);
+ ZFREE(z, z->state);
+ z->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream))
+ return Z_VERSION_ERROR;
+
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->msg = Z_NULL;
+ if (z->zalloc == Z_NULL)
+ {
+ z->zalloc = zcalloc;
+ z->opaque = (voidpf)0;
+ }
+ if (z->zfree == Z_NULL) z->zfree = zcfree;
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Tracev((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ b = NEXTBYTE;
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ if (!(b & PRESET_DICT))
+ {
+ z->state->mode = BLOCKS;
+ break;
+ }
+ z->state->mode = DICT4;
+ case DICT4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = DICT3;
+ case DICT3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = DICT2;
+ case DICT2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = DICT1;
+ case DICT1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+ z->adler = z->state->sub.check.need;
+ z->state->mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z->state->mode = BAD;
+ z->msg = (char*)"need dictionary";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r == Z_OK)
+ r = f;
+ if (r != Z_STREAM_END)
+ return r;
+ r = f;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ uInt length = dictLength;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+ z->adler = 1L;
+
+ if (length >= ((uInt)1<<z->state->wbits))
+ {
+ length = (1<<z->state->wbits)-1;
+ dictionary += dictLength - length;
+ }
+ inflate_set_dictionary(z->state->blocks, dictionary, length);
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateSync(z)
+z_streamp z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ static const Byte mark[4] = {0, 0, 0xff, 0xff};
+ if (*p == mark[m])
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+ return Z_STREAM_ERROR;
+ return inflate_blocks_sync_point(z->state->blocks);
+}
--- /dev/null
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+const char inflate_copyright[] =
+ " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ const uIntf *, /* list of base values for non-simple codes */
+ const uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ inflate_huft *, /* space for trees */
+ uInt *, /* hufts used in space */
+ uIntf * )); /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= 288) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+const uIntf *d; /* list of base values for non-simple codes */
+const uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+inflate_huft *hp; /* space for trees */
+uInt *hn; /* hufts used in space */
+uIntf *v; /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+ lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+ n = x[g]; /* set n to length of v */
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = g - w;
+ z = z > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate new table */
+ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
+ return Z_MEM_ERROR; /* not enough memory */
+ u[h] = q = hp + *hn;
+ *hn += z;
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ j = i >> (w - l);
+ r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ else
+ *t = q; /* first table is returned result */
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ mask = (1 << w) - 1; /* needed on HP, cc -O bug */
+ while ((i & mask) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+ tb, bb, hp, &hn, v);
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR || *bb == 0)
+ {
+ z->msg = (char*)"incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate work area */
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+
+ /* build literal/length tree */
+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+ if (r != Z_OK || *bl == 0)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+ }
+
+ /* build distance tree */
+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+ if (r != Z_OK || (*bd == 0 && nl > 257))
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed distance tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ z->msg = (char*)"incomplete distance tree";
+ r = Z_DATA_ERROR;
+ }
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"empty distance tree with lengths";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+#endif
+ }
+
+ /* done */
+ ZFREE(z, v);
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544 /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z; /* for memory allocation */
+{
+#ifdef BUILDFIXED
+ /* build fixed tables if not already */
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ uInt f = 0; /* number of hufts used in fixed_mem */
+ uIntf *c; /* length list for huft_build */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate memory */
+ if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ {
+ ZFREE(z, c);
+ return Z_MEM_ERROR;
+ }
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 9;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+ fixed_mem, &f, v);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+ fixed_mem, &f, v);
+
+ /* done */
+ ZFREE(z, v);
+ ZFREE(z, c);
+ fixed_built = 1;
+ }
+#endif
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
--- /dev/null
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ uInt pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit int's) */
+ uInt base; /* literal, length base, distance base,
+ or table offset */
+};
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1004 huft structures (850 for length/literals
+ and 154 for distances, the latter actually the result of an
+ exhaustive search). The actual maximum is not known, but the
+ value below is more than safe. */
+#define MANY 1440
+
+extern int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+extern int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+extern int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_streamp)); /* for memory allocation */
--- /dev/null
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt n;
+ Bytef *p;
+ Bytef *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
--- /dev/null
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONE, /* finished last block, done */
+ BAD} /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ inflate_block_mode mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ inflate_huft *hufts; /* single malloc for tree space */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#endif
--- /dev/null
+/* maketree.c -- make inffixed.h table for decoding fixed codes
+ * Copyright (C) 1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* This program is included in the distribution for completeness.
+ You do not need to compile or run this program since inffixed.h
+ is already included in the distribution. To use this program
+ you need to compile zlib with BUILDFIXED defined and then compile
+ and link this program with the zlib library. Then the output of
+ this program can be piped to inffixed.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "zutil.h"
+#include "inftrees.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* generate initialization table for an inflate_huft structure array */
+void maketree(uInt b, inflate_huft *t)
+{
+ int i, e;
+
+ i = 0;
+ while (1)
+ {
+ e = t[i].exop;
+ if (e && (e & (16+64)) == 0) /* table pointer */
+ {
+ fprintf(stderr, "maketree: cannot initialize sub-tables!\n");
+ exit(1);
+ }
+ if (i % 4 == 0)
+ printf("\n ");
+ printf(" {{{%u,%u}},%u}", t[i].exop, t[i].bits, t[i].base);
+ if (++i == (1<<b))
+ break;
+ putchar(',');
+ }
+ puts("");
+}
+
+/* create the fixed tables in C initialization syntax */
+void main(void)
+{
+ int r;
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ z_stream z;
+
+ z.zalloc = zcalloc;
+ z.opaque = (voidpf)0;
+ z.zfree = zcfree;
+ r = inflate_trees_fixed(&bl, &bd, &tl, &td, &z);
+ if (r)
+ {
+ fprintf(stderr, "inflate_trees_fixed error %d\n", r);
+ return;
+ }
+ puts("/* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by the maketree.c program");
+ puts(" */");
+ puts("");
+ puts("/* WARNING: this file should *not* be used by applications. It is");
+ puts(" part of the implementation of the compression library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ printf("local uInt fixed_bl = %d;\n", bl);
+ printf("local uInt fixed_bd = %d;\n", bd);
+ printf("local inflate_huft fixed_tl[] = {");
+ maketree(bl, tl);
+ puts(" };");
+ printf("local inflate_huft fixed_td[] = {");
+ maketree(bd, td);
+ puts(" };");
+}
--- /dev/null
+/* minigzip.c -- simulate gzip using the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * minigzip is a minimal implementation of the gzip utility. This is
+ * only an example of using zlib and isn't meant to replace the
+ * full-featured gzip. No attempt is made to deal with file systems
+ * limiting names to 14 or 8+3 characters, etc... Error checking is
+ * very limited. So use minigzip only for testing; use gzip for the
+ * real thing. On MSDOS, use only on file names without extension
+ * or in pipe mode.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#else
+ extern void exit OF((int));
+#endif
+
+#ifdef USE_MMAP
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <sys/stat.h>
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+#ifdef VMS
+# define unlink delete
+# define GZ_SUFFIX "-gz"
+#endif
+#ifdef RISCOS
+# define unlink remove
+# define GZ_SUFFIX "-gz"
+# define fileno(file) file->__file
+#endif
+#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fileno */
+#endif
+
+#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
+ extern int unlink OF((const char *));
+#endif
+
+#ifndef GZ_SUFFIX
+# define GZ_SUFFIX ".gz"
+#endif
+#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
+
+#define BUFLEN 16384
+#define MAX_NAME_LEN 1024
+
+#ifdef MAXSEG_64K
+# define local static
+ /* Needed for systems with limitation on stack size. */
+#else
+# define local
+#endif
+
+char *prog;
+
+void error OF((const char *msg));
+void gz_compress OF((FILE *in, gzFile out));
+#ifdef USE_MMAP
+int gz_compress_mmap OF((FILE *in, gzFile out));
+#endif
+void gz_uncompress OF((gzFile in, FILE *out));
+void file_compress OF((char *file, char *mode));
+void file_uncompress OF((char *file));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Display error message and exit
+ */
+void error(msg)
+ const char *msg;
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+/* ===========================================================================
+ * Compress input to output then close both files.
+ */
+
+void gz_compress(in, out)
+ FILE *in;
+ gzFile out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+#ifdef USE_MMAP
+ /* Try first compressing with mmap. If mmap fails (minigzip used in a
+ * pipe), use the normal fread loop.
+ */
+ if (gz_compress_mmap(in, out) == Z_OK) return;
+#endif
+ for (;;) {
+ len = fread(buf, 1, sizeof(buf), in);
+ if (ferror(in)) {
+ perror("fread");
+ exit(1);
+ }
+ if (len == 0) break;
+
+ if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
+ }
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+}
+
+#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
+
+/* Try compressing the input file at once using mmap. Return Z_OK if
+ * if success, Z_ERRNO otherwise.
+ */
+int gz_compress_mmap(in, out)
+ FILE *in;
+ gzFile out;
+{
+ int len;
+ int err;
+ int ifd = fileno(in);
+ caddr_t buf; /* mmap'ed buffer for the entire input file */
+ off_t buf_len; /* length of the input file */
+ struct stat sb;
+
+ /* Determine the size of the file, needed for mmap: */
+ if (fstat(ifd, &sb) < 0) return Z_ERRNO;
+ buf_len = sb.st_size;
+ if (buf_len <= 0) return Z_ERRNO;
+
+ /* Now do the actual mmap: */
+ buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
+ if (buf == (caddr_t)(-1)) return Z_ERRNO;
+
+ /* Compress the whole file at once: */
+ len = gzwrite(out, (char *)buf, (unsigned)buf_len);
+
+ if (len != (int)buf_len) error(gzerror(out, &err));
+
+ munmap(buf, buf_len);
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+ return Z_OK;
+}
+#endif /* USE_MMAP */
+
+/* ===========================================================================
+ * Uncompress input to output then close both files.
+ */
+void gz_uncompress(in, out)
+ gzFile in;
+ FILE *out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+ for (;;) {
+ len = gzread(in, buf, sizeof(buf));
+ if (len < 0) error (gzerror(in, &err));
+ if (len == 0) break;
+
+ if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
+ error("failed fwrite");
+ }
+ }
+ if (fclose(out)) error("failed fclose");
+
+ if (gzclose(in) != Z_OK) error("failed gzclose");
+}
+
+
+/* ===========================================================================
+ * Compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+void file_compress(file, mode)
+ char *file;
+ char *mode;
+{
+ local char outfile[MAX_NAME_LEN];
+ FILE *in;
+ gzFile out;
+
+ strcpy(outfile, file);
+ strcat(outfile, GZ_SUFFIX);
+
+ in = fopen(file, "rb");
+ if (in == NULL) {
+ perror(file);
+ exit(1);
+ }
+ out = gzopen(outfile, mode);
+ if (out == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
+ exit(1);
+ }
+ gz_compress(in, out);
+
+ unlink(file);
+}
+
+
+/* ===========================================================================
+ * Uncompress the given file and remove the original.
+ */
+void file_uncompress(file)
+ char *file;
+{
+ local char buf[MAX_NAME_LEN];
+ char *infile, *outfile;
+ FILE *out;
+ gzFile in;
+ int len = strlen(file);
+
+ strcpy(buf, file);
+
+ if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
+ infile = file;
+ outfile = buf;
+ outfile[len-3] = '\0';
+ } else {
+ outfile = file;
+ infile = buf;
+ strcat(infile, GZ_SUFFIX);
+ }
+ in = gzopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
+ exit(1);
+ }
+ out = fopen(outfile, "wb");
+ if (out == NULL) {
+ perror(file);
+ exit(1);
+ }
+
+ gz_uncompress(in, out);
+
+ unlink(infile);
+}
+
+
+/* ===========================================================================
+ * Usage: minigzip [-d] [-f] [-h] [-1 to -9] [files...]
+ * -d : decompress
+ * -f : compress with Z_FILTERED
+ * -h : compress with Z_HUFFMAN_ONLY
+ * -1 to -9 : compression level
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int uncompr = 0;
+ gzFile file;
+ char outmode[20];
+
+ strcpy(outmode, "wb6 ");
+
+ prog = argv[0];
+ argc--, argv++;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "-d") == 0)
+ uncompr = 1;
+ else if (strcmp(*argv, "-f") == 0)
+ outmode[3] = 'f';
+ else if (strcmp(*argv, "-h") == 0)
+ outmode[3] = 'h';
+ else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
+ (*argv)[2] == 0)
+ outmode[2] = (*argv)[1];
+ else
+ break;
+ argc--, argv++;
+ }
+ if (argc == 0) {
+ SET_BINARY_MODE(stdin);
+ SET_BINARY_MODE(stdout);
+ if (uncompr) {
+ file = gzdopen(fileno(stdin), "rb");
+ if (file == NULL) error("can't gzdopen stdin");
+ gz_uncompress(file, stdout);
+ } else {
+ file = gzdopen(fileno(stdout), outmode);
+ if (file == NULL) error("can't gzdopen stdout");
+ gz_compress(stdin, file);
+ }
+ } else {
+ do {
+ if (uncompr) {
+ file_uncompress(*argv);
+ } else {
+ file_compress(*argv, outmode);
+ }
+ } while (argv++, --argc);
+ }
+ exit(0);
+ return 0; /* to avoid warning */
+}
--- /dev/null
+# Makefile for zlib
+# Borland C++
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Borland C 4.5x with the Dos Power Pack for a 32-bit protected mode
+# flat memory model. It was created for use with POV-Ray ray tracer and
+# you may choose to edit the CFLAGS to suit your needs but the
+# switches -WX and -DMSDOS are required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "make -fmakefile.b32"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Borland C++ -------------
+MODEL=-WX
+CFLAGS= $(MODEL) -P-C -K -N- -k- -d -3 -r- -v- -f -DMSDOS
+CC=bcc32
+LD=bcc32
+LIB=tlib
+LDFLAGS= $(MODEL)
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+ del zlib.lib
+ $(LIB) zlib +$(OBJP1)
+ $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
--- /dev/null
+# Makefile for zlib
+# Borland C++ ************ UNTESTED ***********
+
+# To use, do "make -fmakefile.bor"
+# To compile in small model, set below: MODEL=s
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to the LOC macro below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C++, Borland C++ -------------
+
+# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7)
+# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZLIB)
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Memory model: one of s, m, c, l (small, medium, compact, large)
+MODEL=l
+
+CC=bcc
+# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version
+LD=$(CC)
+AR=tlib
+
+# compiler flags
+CFLAGS=-O2 -Z -m$(MODEL) $(LOC)
+# replace "-O2" by "-O -G -a -d" for Turbo C++ 1.0
+
+LDFLAGS=-m$(MODEL)
+
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+ZLIB_H = zlib.h zconf.h
+ZUTIL_H = zutil.h $(ZLIB_H)
+
+ZLIB_LIB = zlib_$(MODEL).lib
+
+all: test
+
+# individual dependencies and action rules:
+adler32.obj: adler32.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c $(ZUTIL_H) infblock.h inftrees.h infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c $(ZUTIL_H) inftrees.h infutil.h infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c $(ZUTIL_H) infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c $(ZUTIL_H) inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c $(ZUTIL_H) inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c $(ZUTIL_H) inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) +$(OBJP1)
+ $(AR) $(ZLIB_LIB) +$(OBJP2)
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
--- /dev/null
+# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.dj2; make test -fmakefile.dj2
+#
+# To install libz.a, zconf.h and zlib.h in the djgpp directories, type:
+#
+# make install -fmakefile.dj2
+#
+# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as
+# in the sample below if the pattern of the DJGPP distribution is to
+# be followed. Remember that, while <sp>'es around <=> are ignored in
+# makefiles, they are *not* in batch files or in djgpp.env.
+# - - - - -
+# [make]
+# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include
+# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib
+# BUTT=-m486
+# - - - - -
+# Alternately, these variables may be defined below, overriding the values
+# in djgpp.env, as
+# INCLUDE_PATH=c:\usr\include
+# LIBRARY_PATH=c:\usr\lib
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lz
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+libz.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env .
+
+.PHONY : uninstall clean
+
+install: $(INCL) $(LIBS)
+ -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH)
+ -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH)
+ $(INSTALL) zlib.h $(INCLUDE_PATH)
+ $(INSTALL) zconf.h $(INCLUDE_PATH)
+ $(INSTALL) libz.a $(LIBRARY_PATH)
+
+uninstall:
+ $(RM) $(INCLUDE_PATH)\zlib.h
+ $(RM) $(INCLUDE_PATH)\zconf.h
+ $(RM) $(LIBRARY_PATH)\libz.a
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) libz.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
--- /dev/null
+# Makefile for zlib. Modified for emx 0.9c by Chr. Spieler, 6/17/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.emx; make test -fmakefile.emx
+#
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) zlib.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
--- /dev/null
+# Makefile for zlib
+# Microsoft C 5.1 or later
+
+# To use, do "make makefile.msc"
+# To compile in small model, set below: MODEL=S
+
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to the LOC macro below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Microsoft C 5.1 and later -------------
+
+# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7)
+# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZLIB)
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Memory model: one of S, M, C, L (small, medium, compact, large)
+MODEL=L
+
+CC=cl
+CFLAGS=-nologo -A$(MODEL) -G$(CPU_TYP) -W3 -Oait -Gs $(LOC)
+#-Ox generates bad code with MSC 5.1
+LIB_CFLAGS=-Zl $(CFLAGS)
+
+LD=link
+LDFLAGS=/noi/e/st:0x1500/noe/farcall/packcode
+# "/farcall/packcode" are only useful for `large code' memory models
+# but should be a "no-op" for small code models.
+
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+ZLIB_H = zlib.h zconf.h
+ZUTIL_H = zutil.h $(ZLIB_H)
+
+ZLIB_LIB = zlib_$(MODEL).lib
+
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+# individual dependencies and action rules:
+adler32.obj: adler32.c $(ZLIB_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+compress.obj: compress.c $(ZLIB_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZLIB_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h $(ZUTIL_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+gzio.obj: gzio.c $(ZUTIL_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+infblock.obj: infblock.c $(ZUTIL_H) infblock.h inftrees.h infcodes.h infutil.h
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+infcodes.obj: infcodes.c $(ZUTIL_H) inftrees.h infutil.h infcodes.h inffast.h
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+inflate.obj: inflate.c $(ZUTIL_H) infblock.h
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+inftrees.obj: inftrees.c $(ZUTIL_H) inftrees.h
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+infutil.obj: infutil.c $(ZUTIL_H) inftrees.h infutil.h
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+inffast.obj: inffast.c $(ZUTIL_H) inftrees.h infutil.h inffast.h
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h $(ZUTIL_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+uncompr.obj: uncompr.c $(ZLIB_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+zutil.obj: zutil.c $(ZUTIL_H)
+ $(CC) -c $(LIB_CFLAGS) $*.c
+
+example.obj: example.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ if exist $(ZLIB_LIB) del $(ZLIB_LIB)
+ lib $(ZLIB_LIB) $(OBJ1);
+ lib $(ZLIB_LIB) $(OBJ2);
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj,,,$(ZLIB_LIB);
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj,,,$(ZLIB_LIB);
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
--- /dev/null
+# Makefile for zlib
+# TurboC 2.0
+
+# To use, do "make -fmakefile.tc"
+# To compile in small model, set below: MODEL=-ms
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C 2.0 -------------
+MODEL=l
+# CFLAGS=-O2 -G -Z -m$(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+CFLAGS=-O2 -G -Z -m$(MODEL)
+CC=tcc -I\tc\include
+LD=tcc -L\tc\lib
+AR=tlib
+LDFLAGS=-m$(MODEL) -f-
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+ZLIB_H = zlib.h zconf.h
+ZUTIL_H = zutil.h $(ZLIB_H)
+
+ZLIB_LIB = zlib_$(MODEL).lib
+
+all: test
+
+adler32.obj: adler32.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c $(ZUTIL_H) infblock.h inftrees.h infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c $(ZUTIL_H) inftrees.h infutil.h infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c $(ZUTIL_H) infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c $(ZUTIL_H) inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c $(ZUTIL_H) inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c $(ZUTIL_H) inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c $(ZUTIL_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c $(ZLIB_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) +$(OBJP1)
+ $(AR) $(ZLIB_LIB) +$(OBJP2)
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) -eexample.exe example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) -eminigzip.exe minigzip.obj $(ZLIB_LIB)
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
--- /dev/null
+# Makefile for zlib
+# Microsoft 32-bit Visual C++ 4.0 or later (may work on earlier versions)
+
+# To use, do "nmake /f makefile.w32"
+
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Microsoft Visual C++ 4.0 and later -------------
+MODEL=
+CFLAGS=-Ox -GA3s -nologo -W3
+CC=cl
+LD=link
+LDFLAGS=
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+ infutil$(O)+inffast$(O)
+
+all: zlib.lib example.exe minigzip.exe
+
+adler32.obj: adler32.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zlib.lib: $(OBJ1) $(OBJ2)
+ if exist zlib.lib del zlib.lib
+ lib /OUT:zlib.lib $(OBJ1) $(OBJ2)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib /OUT:example.exe /SUBSYSTEM:CONSOLE
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib /OUT:minigzip.exe /SUBSYSTEM:CONSOLE
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+#clean:
+# del *.obj
+# del *.exe
--- /dev/null
+# Makefile for zlib
+# Watcom 10a
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Watcom 10a 32-bit protected mode flat memory model. It was created
+# for use with POV-Ray ray tracer and you may choose to edit the CFLAGS to
+# suit your needs but the -DMSDOS is required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "wmake -f makefile.wat"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Watcom 10a -------------
+MODEL=-mf
+CFLAGS= $(MODEL) -fpi87 -fp5 -zp4 -5r -w5 -oneatx -DMSDOS
+CC=wcc386
+LD=wcl386
+LIB=wlib -b -c
+LDFLAGS=
+O=.obj
+
+# variables
+OBJ1=adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O)
+OBJ2=trees$(O) zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O)
+OBJ3=infutil$(O) inffast$(O)
+OBJP1=adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)
+OBJP2=trees$(O)+zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)
+OBJP3=infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h &
+ infcodes.h infutil.h
+ $(CC) $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h &
+ infcodes.h inffast.h
+ $(CC) $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2) $(OBJ3)
+ del zlib.lib
+ $(LIB) zlib.lib +$(OBJP1)
+ $(LIB) zlib.lib +$(OBJP2)
+ $(LIB) zlib.lib +$(OBJP3)
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: minigzip.exe example.exe
+ example
+ echo hello world | minigzip | minigzip -d >test
+ type test
+
+#clean:
+# del *.obj
+# del *.exe
--- /dev/null
+LIBRARY "zlib"
+
+DESCRIPTION '"""zlib data compression library"""'
+
+EXETYPE NT
+
+SUBSYSTEM WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+VERSION 1.13
+
+CODE EXECUTE READ
+
+DATA READ WRITE
+
+HEAPSIZE 1048576,4096
+
+EXPORTS
+ adler32 @1
+ compress @2
+ crc32 @3
+ deflate @4
+ deflateCopy @5
+ deflateEnd @6
+ deflateInit2_ @7
+ deflateInit_ @8
+ deflateParams @9
+ deflateReset @10
+ deflateSetDictionary @11
+ gzclose @12
+ gzdopen @13
+ gzerror @14
+ gzflush @15
+ gzopen @16
+ gzread @17
+ gzwrite @18
+ inflate @19
+ inflateEnd @20
+ inflateInit2_ @21
+ inflateInit_ @22
+ inflateReset @23
+ inflateSetDictionary @24
+ inflateSync @25
+ uncompress @26
+ zlibVersion @27
+ gzprintf @28
+ gzputc @29
+ gzgetc @30
+ gzseek @31
+ gzrewind @32
+ gztell @33
+ gzeof @34
+ gzsetparams @35
+ zError @36
+ inflateSyncPoint @37
+ get_crc_table @38
+ compress2 @39
+ gzputs @40
+ gzgets @41
--- /dev/null
+#include <windows.h>
+
+#define IDR_VERSION1 1
+IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
+ FILEVERSION 1,1,3,0
+ PRODUCTVERSION 1,1,3,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS_DOS_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0 // not used
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ //language ID = U.S. English, char set = Windows, Multilingual
+
+ BEGIN
+ VALUE "FileDescription", "zlib data compression library\0"
+ VALUE "FileVersion", "1.1.3\0"
+ VALUE "InternalName", "zlib\0"
+ VALUE "OriginalFilename", "zlib.dll\0"
+ VALUE "ProductName", "ZLib.DLL\0"
+ VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
+ VALUE "LegalCopyright", "(C) 1995-1998 Jean-loup Gailly & Mark Adler\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+END
--- /dev/null
+# Makefile for zlib. Modified for emx/rsxnt by Chr. Spieler, 6/16/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.emx; make test -fmakefile.emx
+#
+
+CC=gcc -Zwin32
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) zlib.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
+# Makefile for zlib. Modified for emx 0.9c by Chr. Spieler, 6/17/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.emx; make test -fmakefile.emx
+#
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) zlib.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
--- /dev/null
+# Makefile for zlib. Modified for mingw32 by C. Spieler, 6/16/98.
+# (This Makefile is directly derived from Makefile.dj2)
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile, or to compile and test, type:
+#
+# make -fmakefile.gcc; make test -fmakefile.gcc
+#
+# To install libz.a, zconf.h and zlib.h in the mingw32 directories, type:
+#
+# make install -fmakefile.gcc
+#
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+ -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f." If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lz
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+ ./example
+ echo hello world | .\minigzip | .\minigzip -d
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+libz.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+ $(LD) $@ $< $(LDLIBS)
+
+# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env .
+
+.PHONY : uninstall clean
+
+install: $(INCL) $(LIBS)
+ -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH)
+ -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH)
+ $(INSTALL) zlib.h $(INCLUDE_PATH)
+ $(INSTALL) zconf.h $(INCLUDE_PATH)
+ $(INSTALL) libz.a $(LIBRARY_PATH)
+
+uninstall:
+ $(RM) $(INCLUDE_PATH)\zlib.h
+ $(RM) $(INCLUDE_PATH)\zconf.h
+ $(RM) $(LIBRARY_PATH)\libz.a
+
+clean:
+ $(RM) *.d
+ $(RM) *.o
+ $(RM) *.exe
+ $(RM) libz.a
+ $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
--- /dev/null
+# Makefile for zlib
+
+!include <ntwin32.mak>
+
+CC=cl
+LD=link
+CFLAGS=-O -nologo
+LDFLAGS=
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+ trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+ infutil$(O) inffast$(O)
+
+all: zlib.dll example.exe minigzip.exe
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+ infcodes.h infutil.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+ infcodes.h inffast.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+ $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+zlib.dll: $(OBJ1) $(OBJ2) zlib.dnt
+ link $(dlllflags) -out:$@ -def:zlib.dnt $(OBJ1) $(OBJ2) $(guilibsdll)
+
+zlib.lib: zlib.dll
+
+example.exe: example.obj zlib.lib
+ $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+ $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+clean:
+ del *.obj
+ del *.exe
+ del *.dll
+ del *.lib
--- /dev/null
+LIBRARY zlib.dll
+EXETYPE WINDOWS
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+EXPORTS
+ adler32 @1
+ compress @2
+ crc32 @3
+ deflate @4
+ deflateCopy @5
+ deflateEnd @6
+ deflateInit2_ @7
+ deflateInit_ @8
+ deflateParams @9
+ deflateReset @10
+ deflateSetDictionary @11
+ gzclose @12
+ gzdopen @13
+ gzerror @14
+ gzflush @15
+ gzopen @16
+ gzread @17
+ gzwrite @18
+ inflate @19
+ inflateEnd @20
+ inflateInit2_ @21
+ inflateInit_ @22
+ inflateReset @23
+ inflateSetDictionary @24
+ inflateSync @25
+ uncompress @26
+ zlibVersion @27
+ gzprintf @28
+ gzputc @29
+ gzgetc @30
+ gzseek @31
+ gzrewind @32
+ gztell @33
+ gzeof @34
+ gzsetparams @35
+ zError @36
+ inflateSyncPoint @37
+ get_crc_table @38
+ compress2 @39
+ gzputs @40
+ gzgets @41
--- /dev/null
+# Makefile for zlib under OS/2 using GCC (PGCC)
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# cp Makefile.os2 ..
+# cd ..
+# make -f Makefile.os2 test
+
+# This makefile will build a static library z.lib, a shared library
+# z.dll and a import library zdll.lib. You can use either z.lib or
+# zdll.lib by specifying either -lz or -lzdll on gcc's command line
+
+CC=gcc -Zomf -s
+
+CFLAGS=-O6 -Wall
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+#################### BUG WARNING: #####################
+## infcodes.c hits a bug in pgcc-1.0, so you have to use either
+## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem)
+## This bug is reportedly fixed in pgcc >1.0, but this was not tested
+CFLAGS+=-fno-force-mem
+
+LDFLAGS=-s -L. -lzdll -Zcrtdll
+LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll
+
+VER=1.1.0
+ZLIB=z.lib
+SHAREDLIB=z.dll
+SHAREDLIBIMP=zdll.lib
+LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP)
+
+AR=emxomfar cr
+IMPLIB=emximp
+RANLIB=echo
+TAR=tar
+SHELL=bash
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \
+ algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+ nt/Makefile.nt nt/zlib.dnt contrib/README.contrib contrib/*.txt \
+ contrib/asm386/*.asm contrib/asm386/*.c \
+ contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \
+ contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \
+ contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32
+
+all: example.exe minigzip.exe
+
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+$(ZLIB): $(OBJS)
+ $(AR) $@ $(OBJS)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+$(SHAREDLIB): $(OBJS) os2/z.def
+ $(LDSHARED) -o $@ $^
+
+$(SHAREDLIBIMP): os2/z.def
+ $(IMPLIB) -o $@ $^
+
+example.exe: example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip.exe: minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+clean:
+ rm -f *.o *~ example minigzip libz.a libz.so* foo.gz
+
+distclean: clean
+
+zip:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c
+ v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ zip -ul9 zlib$$v $(DISTFILES)
+ mv Makefile~ Makefile
+
+dist:
+ mv Makefile Makefile~; cp -p Makefile.in Makefile
+ rm -f test.c ztest*.c
+ d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+ rm -f $$d.tar.gz; \
+ if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+ files=""; \
+ for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+ cd ..; \
+ GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+ if test ! -d $$d; then rm -f $$d; fi
+ mv Makefile~ Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
--- /dev/null
+;
+; Slightly modified version of ../nt/zlib.dnt :-)
+;
+
+LIBRARY Z
+DESCRIPTION "Zlib compression library for OS/2"
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+EXPORTS
+ adler32
+ compress
+ crc32
+ deflate
+ deflateCopy
+ deflateEnd
+ deflateInit2_
+ deflateInit_
+ deflateParams
+ deflateReset
+ deflateSetDictionary
+ gzclose
+ gzdopen
+ gzerror
+ gzflush
+ gzopen
+ gzread
+ gzwrite
+ inflate
+ inflateEnd
+ inflateInit2_
+ inflateInit_
+ inflateReset
+ inflateSetDictionary
+ inflateSync
+ uncompress
+ zlibVersion
+ gzprintf
+ gzputc
+ gzgetc
+ gzseek
+ gzrewind
+ gztell
+ gzeof
+ gzsetparams
+ zError
+ inflateSyncPoint
+ get_crc_table
+ compress2
+ gzputs
+ gzgets
--- /dev/null
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1998 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is ascii or binary */
+ if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute first the block length in bytes*/
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
--- /dev/null
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
--- /dev/null
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
--- /dev/null
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateReset z_inflateReset
+# define compress z_compress
+# define compress2 z_compress2
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+# ifndef __32BIT__
+# define __32BIT__
+# endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
+# define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+# ifndef STDC
+# define STDC
+# endif
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+# define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+# ifndef __32BIT__
+# define SMALL_MEDIUM
+# define FAR _far
+# endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+# if defined(_WINDOWS) || defined(WINDOWS)
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR _cdecl _export
+# endif
+# endif
+# if defined (__BORLANDC__)
+# if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+# include <windows.h>
+# define ZEXPORT __declspec(dllexport) WINAPI
+# define ZEXPORTRVA __declspec(dllexport) WINAPIV
+# else
+# if defined (_Windows) && defined (__DLL__)
+# define ZEXPORT _export
+# define ZEXPORTVA _export
+# endif
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# if defined (ZLIB_DLL)
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+#endif
+
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(inflate_blocks,"INBL")
+# pragma map(inflate_blocks_new,"INBLNE")
+# pragma map(inflate_blocks_free,"INBLFR")
+# pragma map(inflate_blocks_reset,"INBLRE")
+# pragma map(inflate_codes_free,"INCOFR")
+# pragma map(inflate_codes,"INCO")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_flush,"INFLU")
+# pragma map(inflate_mask,"INMA")
+# pragma map(inflate_set_dictionary,"INSEDI2")
+# pragma map(inflate_copyright,"INCOPY")
+# pragma map(inflate_trees_bits,"INTRBI")
+# pragma map(inflate_trees_dynamic,"INTRDY")
+# pragma map(inflate_trees_fixed,"INTRFI")
+# pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
--- /dev/null
+.TH ZLIB 3 "9 July 1998"
+.SH NAME
+zlib \- compression/decompression library
+.SH SYNOPSIS
+[see
+.I zlib.h
+for full description]
+.SH DESCRIPTION
+The
+.I zlib
+library is a general purpose data compression library.
+The code is thread safe.
+It provides in-memory compression and decompression functions,
+including integrity checks of the uncompressed data.
+This version of the library supports only one compression method (deflation)
+but other algorithms will be added later and will have the same stream interface.
+.LP
+Compression can be done in a single step if the buffers are large enough
+(for example if an input file is mmap'ed),
+or can be done by repeated calls of the compression function.
+In the latter case,
+the application must provide more input and/or consume the output
+(providing more output space) before each call.
+.LP
+The library also supports reading and writing files in
+.I gzip
+(.gz) format
+with an interface similar to that of stdio.
+.LP
+The library does not install any signal handler. The decoder checks
+the consistency of the compressed data, so the library should never
+crash even in case of corrupted input.
+.LP
+All functions of the compression library are documented in the file
+.IR zlib.h.
+The distribution source includes examples of use of the library
+the files
+.I example.c
+and
+.IR minigzip.c .
+.LP
+A Java implementation of
+.IR zlib
+is available in the Java Development Kit 1.1
+.IP
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+.LP
+A Perl interface to
+.IR zlib ,
+written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
+is available at CPAN (Comprehensive Perl Archive Network) sites,
+such as:
+.IP
+ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib*
+.LP
+A Python interface to
+.IR zlib
+written by A.M. Kuchling <amk@magnet.com>
+is available from the Python Software Association sites, such as:
+.IP
+ftp://ftp.python.org/pub/python/contrib/Encoding/zlib*.tar.gz
+.SH "SEE ALSO"
+Questions about zlib should be sent to:
+.IP
+zlib@quest.jpl.nasa.gov
+or, if this fails, to the author addresses given below.
+The zlib home page is:
+.IP
+http://www.cdrom.com/pub/infozip/zlib/
+.LP
+The data format used by the zlib library is described by RFC
+(Request for Comments) 1950 to 1952 in the files:
+.IP
+ftp://ds.internic.net/rfc/rfc1950.txt (zlib format)
+.br
+rfc1951.txt (deflate format)
+.br
+rfc1952.txt (gzip format)
+.LP
+These documents are also available in other formats from:
+.IP
+ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+.SH AUTHORS
+Version 1.1.3
+Copyright (C) 1995-1998 Jean-loup Gailly (jloup@gzip.org)
+and Mark Adler (madler@alumni.caltech.edu).
+.LP
+This software is provided "as-is,"
+without any express or implied warranty.
+In no event will the authors be held liable for any damages
+arising from the use of this software.
+See the distribution directory with respect to requirements
+governing redistribution.
+The deflate format used by
+.I zlib
+was defined by Phil Katz.
+The deflate and
+.I zlib
+specifications were written by L. Peter Deutsch.
+Thanks to all the people who reported problems and suggested various
+improvements in
+.IR zlib ;
+who are too numerous to cite here.
+.LP
+UNIX manual page by R. P. C. Rodgers,
+U.S. National Library of Medicine (rodgers@nlm.nih.gov).
+.\" end of man page
--- /dev/null
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.1.3, July 9th, 1998
+
+ Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.3"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ the compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out).
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may some
+ introduce some output latency (reading input without producing any output)
+ except when forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+ output as possible to the output buffer. The flushing behavior of inflate is
+ not specified for values of the flush parameter other than Z_SYNC_FLUSH
+ and Z_FINISH, but the current implementation actually flushes as much output
+ as possible anyway.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ If a preset dictionary is needed at this point (see inflateSetDictionary
+ below), inflate sets strm-adler to the adler32 checksum of the
+ dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+ it sets strm->adler to the adler32 checksum of all output produced
+ so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+ an error code as described below. At the end of the stream, inflate()
+ checks that its computed adler32 checksum is equal to that saved by the
+ compressor and returns Z_STREAM_END only if the checksum is correct.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect
+ adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+ (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+ enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+ case, the application may then call inflateSync to look for a good
+ compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front.
+
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. If a compressed stream with a larger window size is given as
+ input, inflate() will return with the error code Z_DATA_ERROR instead of
+ trying to allocate a larger window.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+ memLevel). msg is set to null if there is no error message. inflateInit2
+ does not perform any decompression apart from reading the zlib header if
+ present: this will be done by inflate(). (So next_in and avail_in may be
+ modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate
+ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the Adler32 value returned by this call of
+ inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h". (See the description
+ of deflateInit2 for more information about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ const voidp buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int err));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
--- /dev/null
+#include <unistd.h>
+int main() { return 0; }
--- /dev/null
+extern int getchar();
+int hello() {return getchar();}
--- /dev/null
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
--- /dev/null
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#ifdef MSDOS
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+# define OS_CODE 0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0F
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# define fdopen(fd,type) _fdopen(fd,type)
+#endif
+
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+ uInt len));
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
--- /dev/null
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing - GNU libit 0.0"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`configure.in'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`configure.in'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`configure.in'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
--- /dev/null
+#!/bin/sh
+#
+# prepare-clean
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+#
+# Prepares SILC source tree for configuration and compilation. This is
+# done only after checkout from CVS. This is only for developers of SILC
+# and will never appear in public distribution. When creating distributions
+# this is always run first. After the distribution is created all
+# temporary files (including these prepare* scripts) are removed.
+#
+
+echo "Preparing SILC source tree for configuration and compilation..."
+aclocal
+autoconf
+autoheader
+automake
+echo "Done, now run ./configure and make."
--- /dev/null
+#!/bin/sh
+#
+# prepare-clean
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Copyright (C) 2000 Pekka Riikonen
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+#
+# Removes *all* automatically generated files so that after calling this
+# the tree is completely clean and can be prepared for configuration
+# and compilation by calling ./prepare.
+#
+
+echo "Cleaning entire SILC source tree..."
+echo "All errors and warnings may be safely ignored."
+make distclean
+rm -f includes/stamp-*
+rm -f includes/silcconfig.*
+rm -f Makefile.in
+rm -f doc/draft-riikonen*.txt
+rm -f lib/Makefile.in
+rm -f lib/silccore/Makefile.in
+rm -f lib/silccrypt/Makefile.in
+rm -f lib/silcmath/Makefile.in
+rm -f lib/silcsim/Makefile.in
+rm -f lib/silcske/Makefile.in
+rm -f silcd/Makefile.in silcd/log* silcd/*.log
+rm -f silc/Makefile.in silc/log* silc/*.log
+rm -f aclocal.m4
+rm -f configure
+echo "Done."
--- /dev/null
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>About SILC</h1>
+<p>
+SILC (Secure Internet Live Conferencing) is a protocol which provides
+secure conferencing services in the Internet over insecure channel.
+SILC is IRC like softwarre although internally they are very different.
+Biggest similiarity between SILC and IRC is that they both provide
+conferencing services and that SILC has almost same commands as IRC. Other
+than that they are nothing alike. Biggest differences are that SILC is
+secure what IRC is not in any way. The network model is also entirely
+different compared to IRC.
+
+<p>
+<h1>Contact</h1>
+<p>
+Feedback and comments are welcome. You can reach me in the following
+Address.
+<p>
+[Note that generally bug reports should not be sent just yet as the
+Developer's Version is full of them and the bug hunt has not even started
+yet.]
+<p>
+Pekka Riikonen<br>
+priikone@poseidon.pspt.fi
+<p>
+
+</td>
+</tr>
+</table>
+</body>
+</html>
+
--- /dev/null
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1" align=center>
+<tr>
+<td>
+
+<br><br>
+<h1>GNU GENERAL PUBLIC LICENSE</h1>
+<h3>Version 2, June 1991</h3>
+<PRE>
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+</PRE>
+
+
+<H4>Preamble</H4>
+
+<P>
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+</P>
+<P>
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+</P>
+<P>
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+</P>
+<P>
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+</P>
+<P>
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+</P>
+<P>
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+</P>
+<P>
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+</P>
+<P>
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+</P>
+
+
+<H4>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+
+
+<P>
+
+<STRONG>0.</STRONG>
+ This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+<P>
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+<P>
+
+<STRONG>1.</STRONG>
+ You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+<P>
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+<P>
+
+<STRONG>2.</STRONG>
+ You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+<P>
+
+<UL>
+
+<LI><STRONG>a)</STRONG>
+ You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+<P>
+<LI><STRONG>b)</STRONG>
+ You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+<P>
+<LI><STRONG>c)</STRONG>
+ If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+</UL>
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+<P>
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+<P>
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+<P>
+
+<STRONG>3.</STRONG>
+ You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+
+<!-- we use this doubled UL to get the sub-sections indented, -->
+<!-- while making the bullets as unobvious as possible. -->
+<UL>
+
+<LI><STRONG>a)</STRONG>
+ Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+<P>
+<LI><STRONG>b)</STRONG>
+ Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+<P>
+<LI><STRONG>c)</STRONG>
+ Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+</UL>
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+<P>
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+<P>
+
+<STRONG>4.</STRONG>
+ You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+<P>
+
+<STRONG>5.</STRONG>
+ You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+<P>
+
+<STRONG>6.</STRONG>
+ Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+<P>
+
+<STRONG>7.</STRONG>
+ If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+<P>
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+<P>
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+<P>
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+<P>
+
+<STRONG>8.</STRONG>
+ If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+<P>
+
+<STRONG>9.</STRONG>
+ The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+<P>
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+<P>
+
+
+<STRONG>10.</STRONG>
+ If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+
+
+<P><STRONG>NO WARRANTY</STRONG></P>
+
+<P>
+
+<STRONG>11.</STRONG>
+ BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+<P>
+
+<STRONG>12.</STRONG>
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+<P>
+
+
+<H3>END OF TERMS AND CONDITIONS</H3>
+
+</table>
+</body>
+</html>
--- /dev/null
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<font size=4>
+<p>
+<h1>Features</h1>
+<p>
+
+Features to be included into the final release of SILC. [Note that the
+current Developer's Version does not include all of these features, read
+TODO file for more information.]
+<p>
+
+<li>Normal conferencing services such as private messages, channels,
+ channel messages, etc. All traffic is secured and authenticated.
+<p>
+<li>No unique nicknames. There can same nicknames in SILC without
+ collisions. SILC has unique Client ID's, Server ID's and Channel ID's
+ to assure that there are no collisions.
+<p>
+<li>Secure key exchange and authentication protocol. SILC Key Exchange
+ protocol provides key material used in the SILC sessions in secure
+ manner. The protocol is immune for example to man-in-the-middle
+ attacks. The SILC Authentication protocol provides strong
+ authentication. Authentication may be based on passphrase or public
+ key (RSA) authentication. For clients there is an option not to
+ use authentication when connecting to servers.
+<p>
+<li>All traffic is encrypted and authenticated using the best cryptographic
+ algorithms out there. Command messages, private messages and channel
+ messages are all protected by encryption. User can set private keys
+ for both private message and for channels so that even SILC servers do
+ not know the keys. Cipher keys are, by default, 128 bits in length and
+ public keys, by default, 1024 bits in length.
+<p>
+<li>Supports data compression with GZIP to improve performance.
+<p>
+<li>SIM (SILC Module) support. Support for loading of shared objects at
+ run-time that provides new and extended features to both SILC client
+ and server. These can provide extra ciphers and extra features to
+ the software.
+<p>
+<li>SILC client can be installed and used without root privileges.
+<p>
+<li>SILC client can be configured by system wide configuration files but
+ with user specific configuration files as well.
+<p>
+</td>
+</tr>
+</table>
+</body>
+</html>
--- /dev/null
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>History</h1>
+<p>
+Even though SILC were just released to the public the idea and the protocol
+itself is quite old. I got the idea about SILC in its current form in
+the year 1996 and first lines of codes were written in early 1997. This
+release is now third rewrite of the SILC. The very first version were
+written in 1997 and it included SILC client and very very preliminary
+SILC server. The server actually weren't usable but the client looked
+pretty much the same as it does now. At that time the SILC also included
+RSA implementation and 3DES implementation. The random number generator
+that exists in this current release is actually based on the RNG written
+in 1997. The RNG written in 1997, on the other hand, were based on
+the SSH's random number generator. The RNG has been rewritten twice
+since the first version.
+<p>
+I stopped writing the SILC later in 1997 when I got busy at school and
+in work. The pause lasted several months. The development resumed in
+1998 when my friend (Juha Räsänen) and I implemented ElGamal algorithm.
+I rewrote some other parts as well. However, for the same reasons as
+previously the development stopped again. I resumed the development
+later in 1998 by doing rewrite of the SILC in C++. This was obviously
+a mistake but at that time it seemed like a good idea. Again, in the
+winter 1999 I got very busy writing my thesis and was forced to stop the
+development again. I also, started a new job in the spring.
+<p>
+Later, in 1999, I decided that this time I'm going to make it the right
+way. C++ was obviously a bad choice so I decided to fall back to plain
+C language. I also decided to do complete rewrite and started doing
+more thorough planning of what the SILC actually should include. I also
+decided that this time it is going to kill me before I stop the
+development. I started writing SILC in the weekends and actually
+everytime I had some spare time. I also started a new job but I didn't
+let that get to my way. The result of this development effort is the
+release now in public.
+<p>
+I've learned a lot by doing the SILC. I guess, when I started it I wasn't
+that good of a C programmer. That alone was a reason why SILC hasn't
+seen the day of light before now. My programming style has also changed
+dramatically during these years. Actually, it has changed couple times
+since this last rewrite as well. However, the code style of current SILC
+release is quite consistent (actually the coding style SILC has been
+written now I've learned in my current job).
+<p>
+There is probably over 85% of new code in this third rewrite. Rest has
+just been copied from the old versions and only minor changes has been
+made (like changed function names and overall coding style). I've
+preserved the dates of the old files (dating back to 1997) that has
+existed in some forms in the old versions. There is a lot of new code but
+already I see a lot that needs rewriting. The development continues.
+<p>
+</td>
+</tr>
+</table>
+</body>
+</html>
+
--- /dev/null
+<html>
+<header>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<title>SILC - Secure Internet Live Conferencing</title>
+</header>
+
+<body bgcolor="#FFFFFF">
+<center>
+<p><br>
+<img src="silc.jpg" border=0 ALT="SILC Logo">
+<h1>SILC - Secure Internet Live Conferencing</h1>
+<h3>Welcome to the Secure Internet Live Conferencing project homepage</h3>
+<table>
+<tr>
+<td>
+<ul>
+ <li><a href="about.html">About the SILC</a>
+ <li><a href="history.html">History</a>
+ <li><a href="faq.html">The SILC FAQ</a>
+ <li><a href="doc.html">SILC Documentation</a>
+ <li><a href="features.html">SILC Features</a>
+</ul>
+</td>
+<td>
+<ul>
+ <li><a href="download.html">Download SILC</a>
+ <li><a href="todo.html">TODO</a>
+ <li><a href="contribute.html">Contributing</a>
+ <li>Anonymous CVS access [coming]
+ <li><a href="copying.html">The General Public License (GPL)</a>
+</ul>
+</td>
+</tr>
+</table>
+<p><br>
+
+<tr><td align=center>
+<table width="80%" cellspacing=0 cellpadding=0 border=0 bgcolor="#FFFFFF">
+<tr><td bgcolor="#EEEEFF"> <tr><td> </td></tr>
+<tr><td>
+<div style="margin-left: 20px">
+<center><h1>SILC XXXX2000 Development Version Available</h1></center>
+<center>
+<font size=4>
+No, it's not available just yet.
+</center>
+<p><br>
+
+</div>
+</td></tr>
+<tr><td bgcolor="#EEEEFF"> <tr><td> </td></tr>
+<tr><td>
+<div style="margin-left: 20px">
+<center><h1>Developers Wanted For SILC Project</h1></center>
+<center>
+<font size=4>
+XXX
+</center>
+<p><br>
+</div>
+</td></tr>
+</table>
+
+<p>
+<hr width="80%">
+<font size=2>
+<center>
+Webpage by Pekka Riikonen <a href="mailto:priikone@poseidon.pspt.fi">
+priikone@poseidon.pspt.fi</a><br>
+Logos automagically generated with GIMP<br>
+[ <!--#exec cgi="/cgi-bin/textcounter/counter.cgi"--> ] hits since June 12 2000<br>
+Last updated: Mon Jun 12 10:44:06 EEST 2000
+</center>
+</font>
+</body>
+</html>