commit c65f56aefa50a2e2a78a0e45564526ecc921d74f Author: Aris Adamantiadis Date: Tue Jul 5 01:21:44 2005 +0000 first import git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@1 7dcaeef0-15fb-0310-b436-a5af3365683c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..f8e8c28c --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +Author(s): +Aris Adamantiadis (aka spacewalker) + +Contributor(s): +Nick Zitzmann diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 00000000..d6ee962c --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,80 @@ +libssh-0.11-dev +-server implementation development. I won't document it before it even works. +-small bug corrected when connecting to sun ssh servers. +-channel wierdness corrected (writing huge data packets) +-channel_read_nonblocking added +-channel bug where stderr wasn't correctly read fixed. +-sftp_file_set_nonblocking added. It's now possible to have nonblocking SFTP IO +-connect_status callback. +-priv.h contains the internal functions, libssh.h the public interface +-options_set_timeout (thx marcelo) really working. +-tcp tunneling through channel_open_forward. +-channel_request_exec() +-channel_request_env() +-ssh_get_pubkey_hash() +-ssh_is_server_known() +-ssh_write_known_host() +-options_set_ssh_dir +-how could this happen ! there weren't any channel_close ! +-nasty channel_free bug resolved. +-removed the unsigned long all around the code. use only u8,u32 & u64. +-it now compiles and runs under amd64 ! +-channel_request_pty_size +-channel_change_pty_size +-options_copy() +-ported the doc to an HTML file. +-small bugfix in packet.c +-prefixed error constants with SSH_ +-sftp_stat, sftp_lstat, sftp_fstat. thanks Michel Bardiaux for the patch. +-again channel number mismatch fixed. +-fixed a bug in ssh_select making the select fail when a signal has been caught. +-keyboard-interactive authentication working. + +5th march 2004 : libssh-0.1 +-Begining of sftp subsystem implementation. It's stable enough to be used :) +-some cleanup into channels implementation +-Now every channel functions is called by its CHANNEL handler. no any way to play again with numbers. +-added channel_poll() and channel_read(). Now, it's possible to manipulate channel streams only with channel_read() and channel_write(), +with help of channel_poll(). +-changed the client so it uses the new channel_poll and channel_read interface +-small use-after-free bug with channels resolved, and a noninitialised data of SIGNATURE struct. +-changed stupidities in lot of function names. +-removed a debug output file opened by default. +-Added API.txt, the libssh programmer handbook. (I hate documentation) +-Various bug fixes from Nick Zitzmann. Thank to him, libssh now runs under macosX ! +-Developed a cryptographic structure for handling protocols. Adding a custom-based cipher should be the story of thirty +minutes. It now supports aes-256,aes-192,aes-128 and blowfish-128 ! +-An autoconf script which took me half of a day to set up. Respect it! +-A ssh_select wrapper has been written. +It all means the API has changed. not a lot but enough to be incompatible with anything which has been written. + +10th october 2003 : libssh-0.0.4 +-some terminal code (eof handling) added +-channels bugfix (it still needs some tweaking though) +-zlib support +-added a wrapper.c file. The goal is to provide a similar API to every cryptographic functions. bignums and sha/md5 are wrapped now. +-more work than it first looks. +-Support for other crypto libs planed (lighter libs) +-Fixed stupid select() bug. +-libssh now compiles and links with openssl 0.9.6 (but you're advised to upgrade) +-RSA pubkey authentication code now works ! + +15th september 2003 : libssh-0.0.3 +-added install target in makefile +-some cleanup in headers files and source code +-change default banner and project name to libssh. +-new file auth.c to support more and more authentication ways +-bugfix(read offbyone) in send_kex +-a base64 parser. don't read the source, it's awful. pure 0xbadc0de. +-changed the client filename to "ssh". logic isn't it ? +-dss publickey authentication ! still need to wait for the rsa one +-bugfix in packet.c : now packet are completely read (and read blocks if waiting the packet) +-new misc.c contains misc functions + +3rd september 2003: libssh-0.0.2 + initial release. +-client supports both ssh and dss hostkey verification, but doesn't compare +them to openssh's files. (~/.ssh/known_hosts) +-the only supported authentication method is password. +-compiles on linux and openbsd. freebsd and netbsd should work, too +-Lot of work which hasn't been discussed here. diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..b1e3f5a2 --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..0cf1030f --- /dev/null +++ b/Doxyfile @@ -0,0 +1,266 @@ +# Doxyfile 1.3.7-KDevelop + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = libssh.kdevelop +PROJECT_NUMBER = $VERSION$ +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = /home/aris/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = /home/aris/dev/libssh-dev +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.C \ + *.H \ + *.tlh \ + *.diff \ + *.patch \ + *.moc \ + *.xpm \ + *.dox +RECURSIVE = yes +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = yes +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = libssh.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..e3eed952 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,79 @@ +SHELL = /bin/sh +VPATH = @srcdir@ + +subdirs = libssh/ +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +incldir= $(prefix)/include +infodir = $(prefix)/info +libdir = $(prefix)/lib/ +mandir = $(prefix)/man/man1 + +CC = @CC@ +CFLAGS = @CFLAGS@ -Iinclude/ -Wall -g +LDFLAGS = @LDFLAGS@ +LIBS = -lssh -Llibssh/ +INSTALL = @INSTALL@ +LN= @LN_S@ +OBJECTS= sample.o samplesshd.o +VERSION=0.12-dev +DISTLIB=libssh-$(VERSION) +CONFIG=include/libssh/config.h +all: $(CONFIG) $(OBJECTS) + @for dir in ${subdirs}; do \ + (cd $$dir && $(MAKE) all) \ + || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" + $(CC) -o samplessh sample.o $(LDFLAGS) $(LIBS) + $(LN) -sf samplessh samplesftp + $(CC) -o samplesshd samplesshd.o $(LDFLAGS) $(LIBS) +$(CONFIG): + $(LN) -f ../../config.h $(CONFIG) +dist: + rm -fr $(DISTLIB) + mkdir $(DISTLIB) + cp Makefile.in configure.in configure config.h.in install-sh \ + mkinstalldirs config.sub config.guess $(DISTLIB) + mkdir $(DISTLIB)/libssh + mkdir $(DISTLIB)/include + mkdir $(DISTLIB)/include/libssh + mkdir $(DISTLIB)/doc + cp libssh/Makefile.in $(DISTLIB)/libssh/ + cp libssh/*.c $(DISTLIB)/libssh/ + cp include/libssh/libssh.h include/libssh/sftp.h \ + include/libssh/priv.h \ + include/libssh/crypto.h include/libssh/ssh2.h \ + include/libssh/server.h $(DISTLIB)/include/libssh/ + cp *.c COPYING README AUTHORS CHANGELOG $(DISTLIB)/ + cp doc/* $(DISTLIB)/doc/ + tar czf $(DISTLIB).tgz $(DISTLIB)/ +install: all + @for dir in ${subdirs}; do \ + (cd $$dir && $(MAKE) install) \ + || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" + $(top_srcdir)/mkinstalldirs $(incldir)/libssh + $(INSTALL) include/libssh/libssh.h $(incldir)/libssh/ + $(INSTALL) include/libssh/config.h $(incldir)/libssh/ + $(INSTALL) include/libssh/sftp.h $(incldir)/libssh/ + $(INSTALL) include/libssh/crypto.h $(incldir)/libssh/ + $(INSTALL) include/libssh/server.h $(incldir)/libssh/ + $(INSTALL) include/libssh/ssh2.h $(incldir)/libssh/ + $(INSTALL) include/libssh/ssh1.h $(incldir)/libssh/ +clean: + /bin/rm -f *~ *.o ssh sftp + @for dir in ${subdirs}; do \ + (cd $$dir && $(MAKE) clean) \ + || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" + +distclean: clean + /bin/rm -f Makefile config.h config.status config.cache config.log + @for dir in ${subdirs}; do \ + (cd $$dir && $(MAKE) distclean) \ + || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" + diff --git a/README b/README new file mode 100644 index 00000000..e0edfad7 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +The libSSH and its client +~~~~~~~~~~~~~~~~~~~~~~~~~ + -Aris Adamantiadis + +1* Why ? +-_-_-_-_-_ + +Why not ? :) I've began to work on my own implementation of the ssh protocol +because i didn't like the currently public ones. +Not any allow you to import and use the functions as a library, and so i +worked on a library-based SSH implementation. + + +2* How/Who ? +-_-_-_-_-_-_-_ + +If you downloaded this file, you must know what it is : a library for +accessing ssh client services through C libraries calls in a simple manner. +The client is there as a programming example and isn't at all doing its job +correctly (doesn't verify public key hashes with the ones in ~/.ssh/ +and doesn't handle TERM - yet) +Everybody can use this software under the terms of the LGPL - see the COPYING +file + +3* What ? +-_-_-_-_-_ + +The SSH library features : +-Full C library functions for manipulating a client-side SSH connection +-Fully configurable sessions +-Support for AES-128,AES-192,AES-256,blowfish, in cbc mode +-use multiple SSH connections in a same process, at same time. +-usable SFTP implementation +-Public key and password authentication + +4* Where ? +-_-_-_-_-_-_ + +http://0xbadc0de.be/?part=libssh diff --git a/config.guess b/config.guess new file mode 100755 index 00000000..11271623 --- /dev/null +++ b/config.guess @@ -0,0 +1,1415 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2003-10-07' + +# 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. + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# 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 build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +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 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-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 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # 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. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000: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 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + 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=`(sed 1q /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 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${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:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + 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_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + 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 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${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 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + 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:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${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=${UNAME_VERSION}.${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 BSD 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:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + 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 + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + 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_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + 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/iX:*:* | *3000*:MPE/iX:*:*) + 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*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + 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/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + # GNU/KFreeBSD systems have a "k" prefix to indicate we are using + # FreeBSD's kernel, but not the complete OS. + case ${LIBC} in gnu) kernel_only='k' ;; esac + echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + 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:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # 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. + 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:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # 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 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*: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.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-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:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + 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:*:* | R*000: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 ;; + SX-6:SUPER-UX:*:*) + echo sx6-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 ;; + *:Darwin:*:*) + case `uname -p` in + *86) UNAME_PROCESSOR=i686 ;; + powerpc) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[DGKLNPTVWY]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${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 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#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 + 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) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# 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_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 + +# 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 + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000..1c2f7a78 --- /dev/null +++ b/config.h.in @@ -0,0 +1,172 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `endpwent' function. */ +#undef HAVE_ENDPWENT + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `gethostbyaddr' function. */ +#undef HAVE_GETHOSTBYADDR + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `getpass' function. */ +#undef HAVE_GETPASS + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `z' library (-lz). */ +#undef HAVE_LIBZ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_AES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_BLOWFISH_H + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_POLL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_ZLIB_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc diff --git a/config.sub b/config.sub new file mode 100755 index 00000000..79657cd1 --- /dev/null +++ b/config.sub @@ -0,0 +1,1510 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2003-10-07' + +# 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. + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# 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. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +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 + nto-qnx* | linux-gnu* | linux-dietlibc | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + 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 | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + 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/'` + ;; + -udk*) + 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 + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +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. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # 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*86 | x86_64) + 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. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + 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 | j90) + basic_machine=j90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + 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 + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-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 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + 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 + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + 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 + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + 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 + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + 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 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-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/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + 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 + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + 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 + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + 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. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + 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* | -knetbsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -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|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # 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*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -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*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + 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 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-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 + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-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 + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + 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 + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 00000000..18d82055 --- /dev/null +++ b/configure @@ -0,0 +1,6195 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for libssh 0.11-dev . +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='libssh' +PACKAGE_TARNAME='libssh' +PACKAGE_VERSION='0.11-dev ' +PACKAGE_STRING='libssh 0.11-dev ' +PACKAGE_BUGREPORT='aris@0xbadc0de.be' + +ac_unique_file="sample.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os DYLIB_EXTENSION LIBSSH_LDFLAGS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libssh 0.11-dev to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libssh 0.11-dev :";; + esac + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +libssh configure 0.11-dev +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libssh $as_me 0.11-dev , which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ac_config_headers="$ac_config_headers config.h" + + +# Check for the OS. +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +case "$host" in + *-apple*) + DYLIB_EXTENSION="dylib" + LIBSSH_LDFLAGS="-dynamiclib -prebind -seg1addr 0x3a000000 -install_name \"${libdir}/libssh.dylib\" -headerpad_max_install_names -current_version 0.1" + ;; + *) + DYLIB_EXTENSION="so" + LIBSSH_LDFLAGS="-shared" + ;; +esac + + + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_bigendian=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +# It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +int +main () +{ + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6 +case $ac_cv_c_bigendian in + yes) + +cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF + ;; + no) + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + +# Checks for libraries. + +echo "$as_me:$LINENO: checking for BN_init in -lcrypto" >&5 +echo $ECHO_N "checking for BN_init in -lcrypto... $ECHO_C" >&6 +if test "${ac_cv_lib_crypto_BN_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char BN_init (); +int +main () +{ +BN_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_crypto_BN_init=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_crypto_BN_init=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_BN_init" >&5 +echo "${ECHO_T}$ac_cv_lib_crypto_BN_init" >&6 +if test $ac_cv_lib_crypto_BN_init = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCRYPTO 1 +_ACEOF + + LIBS="-lcrypto $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for deflateInit_ in -lz" >&5 +echo $ECHO_N "checking for deflateInit_ in -lz... $ECHO_C" >&6 +if test "${ac_cv_lib_z_deflateInit_+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char deflateInit_ (); +int +main () +{ +deflateInit_ (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_z_deflateInit_=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_z_deflateInit_=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_z_deflateInit_" >&5 +echo "${ECHO_T}$ac_cv_lib_z_deflateInit_" >&6 +if test $ac_cv_lib_z_deflateInit_ = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBZ 1 +_ACEOF + + LIBS="-lz $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for gethostbyname in -lresolv" >&5 +echo $ECHO_N "checking for gethostbyname in -lresolv... $ECHO_C" >&6 +if test "${ac_cv_lib_resolv_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_resolv_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_resolv_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_resolv_gethostbyname" >&6 +if test $ac_cv_lib_resolv_gethostbyname = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRESOLV 1 +_ACEOF + + LIBS="-lresolv $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_nsl_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6 +if test $ac_cv_lib_nsl_gethostbyname = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + +# Checks for header files. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + + + + + + + +for ac_header in fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h \ +sys/time.h termios.h unistd.h openssl/aes.h openssl/blowfish.h zlib.h \ +sys/poll.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------- ## +## Report this to aris@0xbadc0de.be ## +## -------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 +echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6 +if test "${ac_cv_header_time+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_time=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_time=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 +echo "${ECHO_T}$ac_cv_header_time" >&6 +if test $ac_cv_header_time = yes; then + +cat >>confdefs.h <<\_ACEOF +#define TIME_WITH_SYS_TIME 1 +_ACEOF + +fi + + +# Checks for library functions. + +for ac_header in stdlib.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------- ## +## Report this to aris@0xbadc0de.be ## +## -------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5 +echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6 +if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_malloc_0_nonnull=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if STDC_HEADERS || HAVE_STDLIB_H +# include +#else +char *malloc (); +#endif + +int +main () +{ +exit (malloc (0) ? 0 : 1); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_malloc_0_nonnull=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5 +echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6 +if test $ac_cv_func_malloc_0_nonnull = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MALLOC 1 +_ACEOF + +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_MALLOC 0 +_ACEOF + + case $LIBOBJS in + "malloc.$ac_objext" | \ + *" malloc.$ac_objext" | \ + "malloc.$ac_objext "* | \ + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; +esac + + +cat >>confdefs.h <<\_ACEOF +#define malloc rpl_malloc +_ACEOF + +fi + + + +echo "$as_me:$LINENO: checking for working memcmp" >&5 +echo $ECHO_N "checking for working memcmp... $ECHO_C" >&6 +if test "${ac_cv_func_memcmp_working+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_working=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Some versions of memcmp are not 8-bit clean. */ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) + exit (1); + + /* The Next x86 OpenStep bug shows up only when comparing 16 bytes + or more and with at least one buffer not starting on a 4-byte boundary. + William Lewis provided this test program. */ + { + char foo[21]; + char bar[21]; + int i; + for (i = 0; i < 4; i++) + { + char *a = foo + i; + char *b = bar + i; + strcpy (a, "--------01111111"); + strcpy (b, "--------10000000"); + if (memcmp (a, b, 16) >= 0) + exit (1); + } + exit (0); + } + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_memcmp_working=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_memcmp_working=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_memcmp_working" >&5 +echo "${ECHO_T}$ac_cv_func_memcmp_working" >&6 +test $ac_cv_func_memcmp_working = no && case $LIBOBJS in + "memcmp.$ac_objext" | \ + *" memcmp.$ac_objext" | \ + "memcmp.$ac_objext "* | \ + *" memcmp.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; +esac + + + +for ac_header in stdlib.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------- ## +## Report this to aris@0xbadc0de.be ## +## -------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +echo "$as_me:$LINENO: checking for GNU libc compatible realloc" >&5 +echo $ECHO_N "checking for GNU libc compatible realloc... $ECHO_C" >&6 +if test "${ac_cv_func_realloc_0_nonnull+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_realloc_0_nonnull=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if STDC_HEADERS || HAVE_STDLIB_H +# include +#else +char *realloc (); +#endif + +int +main () +{ +exit (realloc (0, 0) ? 0 : 1); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_realloc_0_nonnull=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_realloc_0_nonnull=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_realloc_0_nonnull" >&5 +echo "${ECHO_T}$ac_cv_func_realloc_0_nonnull" >&6 +if test $ac_cv_func_realloc_0_nonnull = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_REALLOC 1 +_ACEOF + +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_REALLOC 0 +_ACEOF + + case $LIBOBJS in + "realloc.$ac_objext" | \ + *" realloc.$ac_objext" | \ + "realloc.$ac_objext "* | \ + *" realloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;; +esac + + +cat >>confdefs.h <<\_ACEOF +#define realloc rpl_realloc +_ACEOF + +fi + + + + + +for ac_header in sys/select.h sys/socket.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------- ## +## Report this to aris@0xbadc0de.be ## +## -------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +echo "$as_me:$LINENO: checking types of arguments for select" >&5 +echo $ECHO_N "checking types of arguments for select... $ECHO_C" >&6 +if test "${ac_cv_func_select_args+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + for ac_arg234 in 'fd_set *' 'int *' 'void *'; do + for ac_arg1 in 'int' 'size_t' 'unsigned long' 'unsigned'; do + for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#if HAVE_SYS_SELECT_H +# include +#endif +#if HAVE_SYS_SOCKET_H +# include +#endif + +int +main () +{ +extern int select ($ac_arg1, + $ac_arg234, $ac_arg234, $ac_arg234, + $ac_arg5); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done + done +done +# Provide a safe default value. +: ${ac_cv_func_select_args='int,int *,struct timeval *'} + +fi +echo "$as_me:$LINENO: result: $ac_cv_func_select_args" >&5 +echo "${ECHO_T}$ac_cv_func_select_args" >&6 +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` +IFS=$ac_save_IFS +shift + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG1 $1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG234 ($2) +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG5 ($3) +_ACEOF + +rm -f conftest* + +echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_signal=void +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_signal=int +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6 + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + + +for ac_func in vprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +echo "$as_me:$LINENO: checking for _doprnt" >&5 +echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6 +if test "${ac_cv_func__doprnt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define _doprnt to an innocuous variant, in case declares _doprnt. + For example, HP-UX 11i declares gettimeofday. */ +#define _doprnt innocuous__doprnt + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef _doprnt + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +char (*f) () = _doprnt; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != _doprnt; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func__doprnt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func__doprnt=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 +echo "${ECHO_T}$ac_cv_func__doprnt" >&6 +if test $ac_cv_func__doprnt = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DOPRNT 1 +_ACEOF + +fi + +fi +done + + + + + + + + + + + + + + + +for ac_func in endpwent gethostbyaddr gethostbyname getpass memmove memset \ + select socket strchr strdup strerror strstr poll +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + ac_config_files="$ac_config_files Makefile libssh/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by libssh $as_me 0.11-dev , which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +libssh config.status 0.11-dev +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "libssh/Makefile" ) CONFIG_FILES="$CONFIG_FILES libssh/Makefile" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@DYLIB_EXTENSION@,$DYLIB_EXTENSION,;t t +s,@LIBSSH_LDFLAGS@,$LIBSSH_LDFLAGS,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@LN_S@,$LN_S,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..59e39b57 --- /dev/null +++ b/configure.in @@ -0,0 +1,60 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libssh, 0.2-dev , aris@0xbadc0de.be) +AC_CONFIG_SRCDIR([sample.c]) +AC_CONFIG_HEADER([config.h]) + +# Check for the OS. +AC_CANONICAL_HOST +case "$host" in + *-apple*) + DYLIB_EXTENSION="dylib" + LIBSSH_LDFLAGS="-dynamiclib -prebind -seg1addr 0x3a000000 -install_name \"${libdir}/libssh.dylib\" -headerpad_max_install_names -current_version 0.1" + ;; + *) + DYLIB_EXTENSION="so" + LIBSSH_LDFLAGS="-shared" + ;; +esac +AC_SUBST(DYLIB_EXTENSION) +AC_SUBST(LIBSSH_LDFLAGS) + +# Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_RANLIB +AC_C_BIGENDIAN + +# Checks for libraries. +AC_CHECK_LIB([crypto], [BN_init]) +AC_CHECK_LIB([z], [deflateInit_]) +AC_CHECK_LIB([resolv],[gethostbyname]) +AC_CHECK_LIB([nsl],[gethostbyname]) + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h \ +sys/time.h termios.h unistd.h openssl/aes.h openssl/blowfish.h zlib.h \ +sys/poll.h ]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_HEADER_TIME + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_FUNC_REALLOC +AC_FUNC_SELECT_ARGTYPES +AC_TYPE_SIGNAL +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([endpwent gethostbyaddr gethostbyname getpass memmove memset \ + select socket strchr strdup strerror strstr poll]) + +AC_CONFIG_FILES([Makefile + libssh/Makefile]) +AC_OUTPUT diff --git a/doc/API.html b/doc/API.html new file mode 100644 index 00000000..033843e3 --- /dev/null +++ b/doc/API.html @@ -0,0 +1,886 @@ + + + + +Libssh's Documentation + + + + +
+
+LIBSSH API GUIDE
+Or everything you ever wanted to know about a simple and fast ssh library. + +
+
+ +

0 Introduction

+ +
+Before inserting ssh hooks into your programs, you must know some basics about +the ssh protocol, and understand why the ssh library must implement them.
+Lot of the protocols specifications are hidden by the ssh library API (of +course !) but some still needs an attention from the end-user programmer.
+Note that libssh is still an alpha product, and the API may vary from one +version to another. The only guess I can make is that the API won't radically +change.
+The SSH protocol was designed for some goals which I resume here :
+-Privacy of data
+-Security
+-Authentication of the server
+-Authentication of the client.
+The client MUST be sure who's speaking to before entering into any +authentication way. That's where the end programmer must ensure the given +fingerprints *are* from the legitimate server. A ssh connection must follow +the following steps:
+
+1- Before connecting the socket, you can set up if you wish one or other + server public key authentication ie. DSA or RSA. + You can choose cryptographic algorithms you trust and compression algorithms + if any.
+2- The connection is made. A secure handshake is made, and resulting from it, + a public key from the server is gained. + You MUST verify that the public key is legitimate.
+3- The client must authenticate : the two implemented ways are password, and + public keys (from dsa and rsa key-pairs generated by openssh). It is + harmless to authenticate to a fake server with these keys because the + protocol ensures the data you sign can't be used twice. It just avoids + man-in-the-middle attacks.
+4- Now that the user has been authenticated, you must open one or several + channels. channels are different subways for information into a single ssh + connection. Each channel has a standard stream (stdout) and an error + stream (stderr). You can theoretically open an infinity of channel.
+5- With the channel you opened, you can do several things :
+ -Open a shell. You may want to request a pseudo virtual terminal before
+ -Execute a command. The virtual terminal is usable, too
+ -Invoke the sftp subsystem. (look at chapter 6)
+ -invoke your own subsystem. This is out the scope of this + document but it is easy to do.
+6- When everything is finished, just close the channels, and then the + connection.
+
+At every place, a function which returns an error code (typically -1 for int +values, NULL for pointers) also sets an error message and an error code. +I high-lined the main steps, now that's you to follow them :) +
+
+

1- Setting the options

+
+The options mechanism will change during updates of the library, but the +functions which exists now will certainly be kept. +

+The ssh system needs to know the preferences of the user, the trust into one +or another algorithm and such. More important informations have to be given +before connecting : the host name of the server, the port (if non default), +the binding address, the default username, ...
+The options structure is given to a ssh_connect function, then this option +structure is used again and again by the ssh implementation. you shall not +free it manually, and you shall not share it with multiple sessions.
+Two ways are given for setting the options : the easy one (of course !) and +the long-but-accurate one.

+
+

a) the easy way


+
+Lot of ssh options in fact come from the command line of the program...
+you could parse them and then use the long way for every argument, but libssh +has a mechanism to do that for you, automatically.
+
+
+SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv); +
+this function will return you a new options pointer based on the arguments +you give in parameters.
better, they clean the argv array from used parameters +so you can use them after in your own program
+
+int main(int argc, char **argv){
+ SSH_OPTIONS *opt;
+ opt=ssh_getopt(&argc, argv);
+ if(!opt){
+ ...
+ }
+
+the function will return NULL if some problem is appearing.
+As a matter of portability for you own programs, the hostname isn't always
+the first argument from the command line, so the single arguments (not +preceded by a -something) won't be parsed.
+
+example:
+user@host:~$ myssh -u aris localhost
+-u aris will be caught, localhost will not.
+
+ +cfr the options_set_user() function in the next part for more informations +about it.
+
+

b) the long way

+
+
+SSH_OPTIONS *options_new(); +
+This function returns an empty but initialized option structure pointer.
+The structure is freed by ssh_disconnect described later, so don't use the +existing function options_free() (it's an internal function).
+So : use it only for one ssh_connect(), never free it.
+
+
+SSH_OPTIONS *options_copy(SSH_OPTIONS *opt); +
+If you need to replicate an option object before using it, use this function. +

+ +The following functions are all of the following form :
+
+int options_set_something(SSH_OPTIONS *opt, something); +
+the something parameters are always internaly copied, so you don't have to +strdup them.
+some return eather 0 or -1, in which case an error message appears in the +error functions, others never fail (return void)
+the error codes and descriptions for these functions are recoverable throught ssh_get_error(NULL); +
+
+int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list); +
+Passing an option structure, a ssh macro for the method, and a list of allowed +parameters indicates libssh you want to use these.
+The macros are :
+KEX_ALGO
+KEX_HOSTKEY Server public key type expected
+KEX_CRYPT_C_S 2 Cryptographic algorithm client->server
+KEX_CRYPT_S_C 3 Cryptographic algorithm server->client
+KEX_MAC_C_S 4
+KEX_MAC_S_C 5
+KEX_COMP_C_S 6 Compression method for the stream ("zlib" or "none"), client to server
+KEX_COMP_S_C 7 Compression method for the stream ("zlib" or "none"), server to client
+KEX_LANG_C_S 8
+KEX_LANG_S_C 9
+
+Currently, only KEX_HOSTKEY and ,KEX_CRYPT_C_S,S_C, KEX_COMP_C_S and S_C work +as expected. the list is a comma separated string of prefered +algorithms/methods, in order of preference.
+
+
+example : this sets the ssh stream to be compressed in client->server mode only +
+ +ret = option_set_wanted_method(options,KEX_COMP_C_S,"zlib"); +
+
+example: this will set the cryptographic algorithms wanted from server to +client to aes128-cbc and then aes192-cbc if the first one isn't supported by +server:
+ret = option_set_wanted_method(options,KEX_CRYPT_S_C,"aes128-cbc,aes192-cbc"); +
+
+if you prefer getting the Dss key from a server instead of rsa, but you still +accept rsa if dss isn't available :
+options_set_wanted_method(options,KEX_HOSTKEY,"ssh-dss,ssh-rsa"); +
+return value:
0 if the option is valid, -1 else.
An error is set in that case. +

+
+void options_set_port(SSH_OPTIONS *opt, unsigned int port); +
+this function sets the server port. +
+void options_set_host(SSH_OPTIONS *opt, const char *hostname); +
+this function sets the hostname of the server. It also supports +"user@hostname" syntax in which case the user options is set too. +
+void options_set_fd(SSH_OPTIONS *opt, int fd); +
+permits you to specify an opened file descriptor you've opened yourself. +
+It's a good way of bypassing the internal FD opening in libssh, but there are things you should take care of :
+-The file descriptor should be returned to libssh without nonblocking settings
+-If you wish to use is_server_known() You should also set options_set_host... Otherwise libssh won't have any mean of certifying the server is known or not.

+
+void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr); +
+this function allows you to set the binding address, in case your computer has +multiple IP or interfaces. it supports both hostnames and IP's +

+
+void options_set_username(SSH_OPTIONS *opt,char *username); +
+sets username for authenticating in this session. +

+ +
+void option_set_timeout(SSH_OPTIONS *opt,long seconds, long usec); +
+sets the timeout for connecting to the socket. It does not include a timeout for the name resolving or handshake. +
+
+
+void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir); +
+this function sets the .ssh/ directory used by libssh. You may use a %s +which will be replaced by the home directory of the user. +NEVER accept parameters others than the user's one, they may contain +format strings which are a security hole if a malicious agent gives it. +

+
+void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir); +
+same than options_set_ssh_dir() for known_hosts file. +

+
+void options_set_identity(SSH_OPTIONS *opt, char *identity); +
+same than upper for the identity file (they come by pair, the one asked is the file without the .pub suffix) +

+
+void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg); +
+Because more and more developpers use libssh with GUI, I've added this function to make the ssh_connect function more +interactive. This permits to set a callback of the form +
void function(void *userarg, float status);
with status going from 0 to 1 during ssh_connect. The callback won't ever be called after the connection is made. +

+
+

+2- Connecting the ssh server +

+
+The API provides an abstract data type, SSH_SESSION, which describes the +connection to one particular server. You can make several connections to +different servers under the same process because of this structure. +
+
+
+SSH_SESSION *ssh_connect(SSH_OPTIONS *options); +
+This function returns a handle on the newly connection. This function expects +to have a pre-set options structure. +
+It returns NULL in case of error, in which case you can look at error messages +for more informations. +

+
+void ssh_disconnect(SSH_SESSION *session); +
+This function sends a polite disconnect message, and does clean the session.
+This is the proper way of finishing a ssh connection.
+
+
+int ssh_get_pubkey_hash(SSH_SESSION *session, char hash[MD5_DIGEST_LEN]); +
+This function places the MD5 hash of the server public key into the hash array.
+It's IMPORTANT to verify it matches the previous known value. One server always +have the same hash. No other server/attacker can emulate it (or it'd be caught +by the public key verification procedure automatically made by libssh). +
+You can skip this step if you correctly handle is_server_known() +

+
+int ssh_is_server_known(SSH_SESSION *session); +
+ +Checks the user's known host file to look for a previous connection to the specified server. Return values:
+SSH_SERVER_KNOWN_OK : the host is known and the key has not changed
+SSH_SERVER_KNOWN_CHANGED : The host's key has changed. Either you are under +an active attack or the key changed. The API doesn't give any way to modify the key in known hosts yet. I Urge end developers to WARN the user about the possibility of an attack.
+SSH_SERVER_FOUND_OTHER: The host gave us a public key of one type, which does +not exist yet in our known host file, but there is an other type of key which is know.
+IE server sent a DSA key and we had a RSA key.
+Be carreful it's a possible attack (coder should use option_set_wanted_method() to specify +which key to use).
+SSH_SERVER_NOT_KNOWN: the server is unknown in known hosts. Possible reasons : +case not matching, alias, ... In any case the user MUST confirm the Md5 hash is correct.
+SSH_SERVER_ERROR : Some error happened while opening known host file.
+
+
+int ssh_write_knownhost(SSH_SESSION *session); +
+write the current connected host as known in the known host file. returns a negative value if something went wrong. You generaly use it when ssh_is_server_known returned SSH_SERVER_NOT_KNOWN. +

+
+int pubkey_get_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]); +
+deprecated but left for binary compatibility (will be removed in newer versions). +
+ +

3- Authenticating to server

+
+The ssh library supports the two most used authentication methods from SSH. +In every function, there is a "username" argument. If null is given instead, +the server will use the default username (which is guessed from what you gave +to options_set_user or options_set_hostname or even the local user running the code). +
+ +Authentication methods :
+

A) Public keys


+ The public key is the only method which does not compromise your key if the + remote host has been compromised (the server can't do anything more than + getting your public key). This is not the case of a password authentication + (the server can get your plaintext password).
+ Libssh is obviously fully compatible with the openssh public and private keys.
+ The things go this way : you scan a list of files which contain public keys.
+ For each key, you send it to ssh server until the server acknowledges a key + (a key it knows). Then, you get the private key for this key and send a + message proving you own that private key.
+ Here again, two ways for the public key authentication... the easy and the + complicated one.
+
+

easy way:

+
+int ssh_userauth_autopubkey(SSH_SESSION *session); +
+This function will try the most common places for finding the public and + private keys (your home directory) or eventualy the identity files asked by + the options_set_identity() function.
+ The return values are :
+ SSH_AUTH_ERROR : some serious error happened during authentication
+ SSH_AUTH_DENIED : no key matched
+ SSH_AUTH_SUCCESS : you are now authenticated
+ SSH_AUTH_PARTIAL : some key matched but you still have to give an other mean + of authentication (like password).
+
+

peanful way:

+ there are three steps : you get a public key, you ask the server if the key + matches a known one, if true, you get the private key and authenticate with + it.
+
+ STRING *publickey_from_file(char *filename,int *_type); +
+will return an handle on a public key. if you give a pointer to an int, + a symbolic value will be placed there. Do it because you need it in next + step.

+
+ int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username, + int type, STRING *publickey); +
+ this function will offer a public key to the server. SSH_AUTH_SUCCESS is + returned if the key is accepted (in which case you'll want to get the + private key), SSH_AUTH_DENIED otherwise.
+ Still watch for SSH_AUTH_ERROR as connection problems might happen. +
+ in case of SSH_AUTH_SUCCESS, +
+
+ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename, + int type,char *passphrase); +
+ will get the privatekey from the filename previously set by + publickey_from_next_file(). You can call it with a passphrase for + unlocking the key. If passphrase==NULL, the default prompt will be used.
+ The function returns NULL if the private key wasn't opened + (ie bad passphrase or missing file).
+
+
+ int ssh_userauth_pubkey(SSH_SESSION *session, char *username, + STRING *publickey, PRIVATE_KEY *privatekey); +
+ Will try to authenticate using the public and private key. It shall return + SSH_AUTH_SUCCESS if you are authenticated, SSH_AUTH_ERROR, SSH_AUTH_DENIED or + SSH_AUTH_PARTIAL depending of return condition.
+ + each public key (of type STRING) must be freed with the libc "free" function.
+ The private key must be freed with private_key_free(PRIVATE_KEY *) which + will clean the memory before (don't worry about passphrase leaking).
+
+ +

B) Password


+
+ int ssh_userauth_password(SSH_SESSION *session,char *username,char *password); +
+ Will return SSH_AUTH_SUCCESS if the password matched, one of other constants + otherwise. It's your work to ask the password and to free it in a secure + manner.

+ +

C) Keyboard-interactive


+
+ int ssh_userauth_kbdint(SSH_SESSION *session, char *user, char *submethods); +
+ This is the main keyboard-interactive function. It will return SSH_AUTH_SUCCESS,SSH_AUTH_DENIED, SSH_AUTH_PARTIAL, SSH_AUTH_ERROR depending on the result of the request.
+ The keyboard-interactive authentication method of SSH2 is a feature which permits the server to ask a certain number of questions in an interactive manner to the client, until it decides to accept or deny the login.
+ To begin, you call this function (you can omit user if it was set previously and omit submethods - instead you know what you do - just put them to NULL) and store the answer. + If the answer is SSH_AUTH_INFO, it means the server has sent a few questions to ask your user, which you can retrieve with the following functions. Then, set the answers and call back ssh_userauth_kbdint with same arguments. It may again ask a few other questions etc. until you get an other SSH_AUTH code than SSH_AUTH_INFO.
+ Few remarks :
+ -Even the first call can return SSH_AUTH_DENIED or SSH_AUTH_SUCCESS.
+ -The server can send an empty question set (this is the default behavior on my system) after you have sent the answers to the first questions. + you must still parse the answer, it might contain some message from the server saying hello or such things. Just call ssh_userauth_kbdint() once more
+
+
+int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session); +
+After you called ssh_userauth_kbdint and got SSH_AUTH_INFO, the session contains a few questions (or prompts) from the server. This function returns the number of prompts and answers.
+It could be zero, in which case you must act as said previously.
+ +
+ char *ssh_userauth_kbdint_getname(SSH_SESSION *session); +
+ this functions returns the "name" of the message block. The meaning is explained later.
+ This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.
+ +
+ char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session); +
+ this functions returns the "instruction" of the message block. The meaning is explained later.
+This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.
+ +
+ char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session,int i, char *echo); +
+This functions returns a pointer to the nth prompt. The character pointed by echo, if different from null, will contain a boolean value after the call, which means that the user prompt must be echoed or not.
+zero means that the echo is Off (like for a password prompt).
+any other value means the echo is on.
+This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.
+ +
+void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *a +nswer); +
+This function sets the ith answer. The string you give will be duplicated, and this copy will be discarded once it is no longer necessary.
+care must be taken so you discard the content of the original string after this function call.
+ +

A little note about how to use the informations from keyboard-interactive authentication

+
+The words from the original drafts explain everything +
+3.3 User Interface + +Upon receiving a request message, the client SHOULD prompt the user +as follows:
+ A command line interface (CLI) client SHOULD print the name and + instruction (if non-empty), adding newlines. Then for each prompt in + turn, the client SHOULD display the prompt and read the user input.
+
+A graphical user interface (GUI) client has many choices on how to +prompt the user. One possibility is to use the name field (possibly +prefixed with the application's name) as the title of a dialog window +in which the prompt(s) are presented. In that dialog window, the +instruction field would be a text message, and the prompts would be +labels for text entry fields. All fields SHOULD be presented to the +user, for example an implementation SHOULD NOT discard the name field +because its windows lack titles; it SHOULD instead find another way +to display this information. If prompts are presented in a dialog +window, then the client SHOULD NOT present each prompt in a separate +window.
+
+All clients MUST properly handle an instruction field with embedded +newlines. They SHOULD also be able to display at least 30 characters +for the name and prompts. If the server presents names or prompts +longer than 30 characters, the client MAY truncate these fields to +the length it can display. If the client does truncate any fields, +there MUST be an obvious indication that such truncation has occured.
+The instruction field SHOULD NOT be truncated.
+Clients SHOULD use control character filtering as discussed in +[SSH-ARCH] to avoid attacks by including terminal control characters +in the fields to be displayed.
+
+For each prompt, the corresponding echo field indicates whether or +not the user input should be echoed as characters are typed. Clients +SHOULD correctly echo/mask user input for each prompt independently +of other prompts in the request message. If a client does not honor +the echo field for whatever reason, then the client MUST err on the +side of masking input. A GUI client might like to have a checkbox +toggling echo/mask. Clients SHOULD NOT add any additional characters +to the prompt such as ": " (colon-space); the server is responsible +for supplying all text to be displayed to the user. Clients MUST +also accept empty responses from the user and pass them on as empty +strings.
+ +
+
+

D) "none"


+ In fact this mode only serve to get the list of supported authentications.
+ however, it also serves to get the banner message from the server, if any.
+ You should firstly try this method, at least for getting the banner, then to enter if there is no password at all.
+
+ int ssh_userauth_none(SSH_SESSION *session, char *username); +
+ if the account has no password (and the server is configured to let you + pass), the function might answer SSH_AUTH_SUCCESS. That's why + ssh_auth_autopubkey already calls it for you. +

+
+ char *ssh_get_issue_banner(SSH_SESSION *session); +
+if during authentication, the server has given a banner, you can get it + this way. the function returns NULL if no banner exists, and you have to + free the returned pointer.

+
+ +

4- Opening a channel

+
+Maybe you want to use the sftp subsystem : all this is done for you, you +better read at the end of the paper how to use the sftp functions.
+You probably want to open one or more shells, or call one or more programs.
+ +So you need a channel.
+
+ CHANNEL *channel; +
+This is an handler to a channel object. it describes your channel. +
+
+CHANNEL *channel_open_session(SSH_SESSION *session); +
+This will open a channel for use into a session (which can be used for executing +a command or a shell. Not for tcp forwarding).
+The function returns NULL if for a reason or another the channel can't be +opened.
+ +CHANNEL *open_session_channel(...) is deprecated and should not be used in future +applications.

+
+CHANNEL *channel_open_forward(SSH_SESSION *session, char *remotehost, + int remoteport, char *sourcehost, int localport); +
+Ask the server to tunnel a TCP connection. The server will connect to + remotehost:remoteport and libssh will return an handle to the channel if it is allowed.
+ Otherwise, NULL will be returned. sourcehost and localport are generaly + used in message debugging purpose and have no effect on the result.
+
+When you've finished with your channel, you may send an EOF message and +then close it :
+
+void channel_send_eof(CHANNEL *channel); +
+sends an end of file into channel. It doesn't close the channel and you can still read it.

+ +
+void channel_free(CHANNEL *channel); +
+closes and destroy the channel. +
+
+void channel_close(CHANNEL *channel); +
+sends an EOF and close the channel. (if you don't know what to do, use channel_free). It doesn't free the channel. + +
+

5- The shell

+
+
+int channel_request_env(CHANNEL *channel, char *name, char *value); +
+Ask the server to set the "name" environment variable to "value". For security + reasons, some variables won't be accepted by the server. It returns 0 otherwise.

+
+int channel_request_pty(CHANNEL *channel); +
+ ask the server to allocate a pseudo terminal for the current channel.
+ the function returns 0 on success.

+ +
+int channel_request_pty_size(CHANNEL *channel, char *terminal, int cols, int rows); +
+ask the server to allocate a pty. The terminal parameter is the type of pty +(vt100,xterm,...), cols and rows are the size of the new terminal (80x24 by example).

+
+int channel_change_pty_size(CHANNEL *channel, int cols,int rows); +
+changes the window size (terminal) of the current session;

+
+int channel_request_shell(CHANNEL *channel); +
+This function requests a shell. After its success, a shell is running at the other side of the channel.

+
+int channel_request_exec(CHANNEL *channel, char *cmd); +
+run a shell command without an interactive shell, ie $SHELL -c "command".
+ returns 0 on success.

+ +You might ask the server to open a subsystem for you. this is done this way : +
+int channel_request_subsystem(CHANNEL *channel, char *subsystem); +
+There are some functions used to manipulate the channels : +

+
+int channel_write(CHANNEL *channel,void *data,int len); +
+writes len bytes of data into the channel. It returns the number of bytes written. The current implementation is a blocking write +of the complete data buffer, but it may vary.

+
+int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr); +
+It makes a blocking read on the channel, of "bytes" bytes and returns the + result into an allocated buffer you passed in. (with buffer_new()).
+ it will read on stderr, if is_stderr is set.
+ The function might read less bytes than "bytes" variable if an End of File + happened. Otherwise, the function will always block reading until "bytes" + bytes are read.
+ with "bytes"=0, channel_read() will read the current state of the read buffer, but will read at least one byte (and block if nothing is available, except EOF case).
+ + You don't need to free and allocate a new buffer each time you call this function, just pass the same object each time.
+ look at the buffer_ functions further for the correct way of retrieving the data.

+ +
+int channel_read_nonblocking (CHANNEL *channel, char *dest, int len, int is_stderr); +
+Non-blocking read on channel, at most len bytes of data are read. Returns 0 if EOF or if no data available. +

+
+int channel_is_open(CHANNEL *channel); +
+ returns 0 if the channel has been closed by remote host, something else otherwise.

+
+int channel_poll(CHANNEL *channel, int is_stderr); +
+ This nonblocking function returns the number of bytes immediatly available for + reading on the channel and stdin/stderr.

+ +More interesting, if you are going to do channel multiplexing, this function +is for you :

+
+int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, + fd_set *readfds, struct timeval *timeout); +
+channels is an array of channel pointers, finished by a NULL pointer.
+ It can be used ever and ever, as it is never written.
+ outchannels is an array of size at least greater or equal to "channels".
+ It hasn't to be initialized.
+ maxfd is the maximum file descriptor from your own filedescriptors.
+ readfds is a pointer to a fd_set structure, like in the original + select implementation (man select).
+ the struct timeval *timeout has the same meaning than in + select(2) (man select).
+ + There is no support for writing or special events as in select(2) yet.
+The function returns -1 if an error occured, or SSH_EINTR if select was interrupted by a syscall. This is not an error, you may restart the function.
+note about signals: libssh is not threadsafe, and most functions are not +reetrant when using the same data structures : it means you *cannot* do anything +with a channel from a ssh session passed to ssh_select during a signal. +
take a look at sample.c on how to bypass that limitation.
+the function works this way : it returns in the readfds the filedescriptors which have data ready for reading (the given filedescriptors have a greatest priority).
+Then, if no file descriptor can be read, the function looks for every +channel from the array to get a channel with data bufferized. If nothing is +available, it waits for activity on any channel/file descriptor and returns +immediatly, or waits until timeout.
+You will find the channels that can be read in the outchannels array (finished by NULL) and the filedescriptors in your fd_set (man FD_ISSET).
+this is the "heart" of your main loop.
+
+

The BUFFER object.

+Reading is done through the BUFFER object. here is the public interface : +
+
+BUFFER *buffer_new(); +
+creates a buffer object. +

+
+void *buffer_get(BUFFER *buffer); +
+returns a pointer to the begining of buffer. +

+
+int buffer_get_len(BUFFER *buffer); +
+returns buffer's data size. +

+
+void buffer_free(BUFFER *buffer); +
+destoys the buffer. +
+
+How to use the buffer system when you've read something:
+I've seen people doing such code:
+
+char buffer[256];
+channel_read(channel,buf,1234,0);
+strcpy(buffer,buf.data);
+
+The correct way of doing this: +
+char buffer[256];
+int i;
+i=channel_read(channel,buf,1234,0);
+if(i<=0)
+    go_out()...
+if(i>=256)
+    i=255;
+memcpy(buffer,buffer_get(buf),i);
+buffer[i]=0; +
+Do not expect the buffer to be null-terminated. Don't access the internal structure of buffer. Check the sizes before copying.
+
+

6- The SFTP subsystem

+
+SFTP is a secure implementation of a file transfer protocol. The current +implemented version is 3. All functions aren't implemented yet but the most +important are.
+
+

A) Opening the session

+
+ SFTP_SESSION *sftp_new(SSH_SESSION *session); + int sftp_init(SFTP_SESSION *sftp); +
+ The former returns a SFTP_SESSION handle. It returns NULL if things didn't + work as expected.
+ sftp_init makes some initialisation work. It returns 0 if things went right. + Both of them must be called.
+

B) Opening and reading a directory

+
+ SFTP_DIR *sftp_opendir(SFTP_SESSION *session, char *path); +
+ opens a directory for file listing. Returns NULL in error case. +

+
+ SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir); +
+This function reads one file attribute from an opened directory. It + returns NULL if the directory is EOF, or if something wrong happened. +

+
+ int sftp_dir_eof(SFTP_DIR *dir); +
+ When a sftp_readdir() returned NULL, you can use this function to + tell if an EOF occured. the function returns 0 if no EOF occured. +

+
+ void sftp_attributes_free(SFTP_ATTRIBUTES *file); +
+You have to free any SFTP_ATTRIBUTE structure given by an other function + with it.

+
+ int sftp_dir_close(SFTP_DIR *dir); +
+closes an opened directory. returns 0 when no error occured. +

+

C) Opening, reading, writing files

+
+ SFTP_FILE *sftp_open(SFTP_SESSION *session, char *file, int access, + SFTP_ATTRIBUTES *attr); +
+Opens a file. The access flags are the same than the stdio flags.
+see open(2) for more details.
+attr are the wanted attributes for the new file. If you supply NULL, + default values will be used.
+rem: more work is going on parsing/making the attributes structure +

+
+ int sftp_read(SFTP_FILE *file, void *dest, int len); +
+read on a file. Works as the fread() function. It is blocking by default but you can change the default behaviour with sftp_file_set_nonblocking(). +

+
+ void sftp_file_set_nonblocking(SFTP_FILE *file); +
+sets the file non blocking. reads on this file won't ever block. You can't detect end of files this way.
+*** TODO more work going there for EOF **** +

+
+ void sftp_file_set_blocking(SFTP_FILE *file); +
+restore the default setting of sftp_read. +

+
+ int sftp_write(SFTP_FILE *file, void *source, int len); +
+works as fwrite() function. It is a blocking write.
+
+
+ void sftp_seek(SFTP_FILE *file, int new_offset); +
+seek into the file for reading/writing at an other place. +

+
+ unsigned long sftp_tell(SFTP_FILE *file); +
+returns the current offset (both writing and reading) into the opened file. +

+
+ void sftp_rewind(SFTP_FILE *file); +
+ same as sftp_seek(file,0); +

+
+ int sftp_file_close(SFTP_FILE *file); +
+ closes a file handle. returns 0 in no error case. +

+
+ int sftp_rm(SFTP_SESSION *sftp, char *file); +
+deletes a file. +

+
+ int sftp_rmdir(SFTP_SESSION *sftp, char *directory); +
+
+deletes a directory. +

+
+ int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr); +
+makes a directory, with the given attributes. You can't pass NULL for attr and hope it works. +

+
+ int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname); +
+changes the name of a file or directory. +

+
+ int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr); +
+changes the attributes of a file or directory. +

+
+ char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path); +
+ gives the canonicalized form of some path. You have to + free the pointer given in return.
+ (returns NULL if error). +

+ + (a function to make proper SFTP_ATTRIBUTES structures is on the way ) + +

D) Closing the session

+
+ void sftp_free(SFTP_SESSION *sftp); +
+it closes the sftp channel and subsystem. +
+ +

7- Handling the errors

+
+When some function returns an error code, it's allways possible to get an +english message describing the problem. the function ssh_get_error() +returns a pointer to the static error buffer.
+ssh_error_code() returns the error code number. it's declared as an enum:
+SSH_NO_ERROR, SSH_REQUEST_DENIED, SSH_INVALID_REQUEST, SSH_CONNECTION_LOST, +SSH_FATAL, SSH_INVALID_DATA.

+SSH_REQUEST_DENIED means the ssh server refused your request but the situation is +recoverable. the others mean something happened to the connection (some +encryption problems, server problems, library bug, ...).
+SSH_INVALID_REQUEST means the library got some garbage from server. (But might be +recoverable).
+SSH_FATAL means the connection has an important problem and isn't probably +recoverable.
+
+Most of time, the error returned are SSH_FATAL, but some functions (generaly the +ssh_request_* ones) may fail because of server denying request. In these cases, SSH_REQUEST_DENIED is returned.

+ +You'll see in the prototype SSH_SESSION *session. That's because for thread +safety, error messages that can be attached to a session aren't static +anymore. So, any error that could happen during ssh_getopt(), options_* or +ssh_connect() will be retreavable giving NULL as argument.
+
+
+char *ssh_get_error(SSH_SESSION *session); +
+returns a pointer to a static message error from the given session. No +message freeing is needed.

+
+enum ssh_error ssh_get_error_code(SSH_SESSION *session); +
+returns the error code that last happened along with the message. +

+
+ +

8- Final word

+
+I made this library because nothing in the Open source or free software community was existing yet. This project is a very personnal one as it's the first "useful" thing I ever wrote. +I hope it fits your needs, but remember the experimental state of libssh : if +something doesn't work, please mail me. If something lacks, please ask for it. +If something stinks, please write a patch and send it ! +
+ + + diff --git a/doc/base64.txt b/doc/base64.txt new file mode 100644 index 00000000..48eafabe --- /dev/null +++ b/doc/base64.txt @@ -0,0 +1,107 @@ + The Base64 Content-Transfer-Encoding is designed to represent + arbitrary sequences of octets in a form that need not be humanly + readable. The encoding and decoding algorithms are simple, but the + encoded data are consistently only about 33 percent larger than the + unencoded data. This encoding is virtually identical to the one used + in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421. + The base64 encoding is adapted from RFC 1421, with one change: base64 + eliminates the "*" mechanism for embedded clear text. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + NOTE: This subset has the important property that it is + represented identically in all versions of ISO 646, including US + ASCII, and all characters in the subset are also represented + identically in all versions of EBCDIC. Other popular encodings, + such as the encoding used by the uuencode utility and the base85 + encoding specified as part of Level 2 PostScript, do not share + these properties, and thus do not fulfill the portability + requirements a binary transport encoding for mail must meet. + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + When encoding a bit stream via the base64 encoding, the bit stream + must be presumed to be ordered with the most-significant-bit first. + + That is, the first bit in the stream will be the high-order bit in + the first byte, and the eighth bit will be the low-order bit in the + first byte, and so on. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. These characters, identified in Table 1, below, are + selected so as to be universally representable, and the set excludes + characters with particular significance to SMTP (e.g., ".", CR, LF) + and to the encapsulation boundaries defined in this document (e.g., + "-"). + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + The output stream (encoded bytes) must be represented in lines of no + more than 76 characters each. All line breaks or other characters + not found in Table 1 must be ignored by decoding software. In base64 + data, characters other than those in Table 1, line breaks, and other + white space probably indicate a transmission error, about which a + warning message or even a message rejection might be appropriate + under some circumstances. + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a body. When fewer than 24 input bits + are available in an input group, zero bits are added (on the right) + to form an integral number of 6-bit groups. Padding at the end of + the data is performed using the '=' character. Since all base64 + input is an integral number of octets, only the following cases can +arise: (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded output will be + an integral multiple of 4 characters with no "=" padding, (2) the + final quantum of encoding input is exactly 8 bits; here, the final + unit of encoded output will be two characters followed by two "=" + padding characters, or (3) the final quantum of encoding input is + exactly 16 bits; here, the final unit of encoded output will be three + characters followed by one "=" padding character. + + Because it is used only for padding at the end of the data, the + occurrence of any '=' characters may be taken as evidence that the + end of the data has been reached (without truncation in transit). No + such assurance is possible, however, when the number of octets + transmitted was a multiple of three. + + Any characters outside of the base64 alphabet are to be ignored in + base64-encoded data. The same applies to any illegal sequence of + characters in the base64 encoding, such as "=====" + + Care must be taken to use the proper octets for line breaks if base64 + encoding is applied directly to text material that has not been + converted to canonical form. In particular, text line breaks must be + converted into CRLF sequences prior to base64 encoding. The important + thing to note is that this may be done directly by the encoder rather + than in a prior canonicalization step in some implementations. + + NOTE: There is no need to worry about quoting apparent + encapsulation boundaries within base64-encoded parts of multipart + entities because no hyphen characters are used in the base64 + encoding. diff --git a/doc/draft-ietf-secsh-agent-01.txt b/doc/draft-ietf-secsh-agent-01.txt new file mode 100644 index 00000000..4c67b724 --- /dev/null +++ b/doc/draft-ietf-secsh-agent-01.txt @@ -0,0 +1,647 @@ +Network Working Group Tatu Ylonen +INTERNET-DRAFT Timo J. Rinne +draft-ietf-secsh-agent-01.txt Sami Lehtinen +Expires in six months SSH Communications Security + 20 November, 2002 + + + + Secure Shell Authentication Agent Protocol + +Status of This Memo + +This document is an Internet-Draft and is in full conformance +with all provisions of Section 10 of RFC2026. + +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." + +The list of current Internet-Drafts can be accessed at +http://www.ietf.org/ietf/1id-abstracts.txt + +The list of Internet-Draft Shadow Directories can be accessed at +http://www.ietf.org/shadow.html. + +Abstract + +This document describes the Secure Shell authentication agent protocol +(i.e., the protocol used between a client requesting authentication and +the authentication agent). This protocol usually runs in a machine-spe- +cific local channel or over a forwarded authentication channel. It is +assumed that the channel is trusted, so no protection for the communica- +tions channel is provided by this protocol. + + + + + + + + + + + + + + + + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 1] + +INTERNET-DRAFT 20 November, 2002 + +Table of Contents + +1. Authentication Agent Protocol . . . . . . . . . . . . . . . . . 2 + 1.1. Packet Format . . . . . . . . . . . . . . . . . . . . . . . 2 + 1.2. Forwarding Notices . . . . . . . . . . . . . . . . . . . . . 3 + 1.3. Requesting Version Number . . . . . . . . . . . . . . . . . 3 + 1.4. Adding Keys to the Agent . . . . . . . . . . . . . . . . . . 4 + 1.5. Deleting Keys from the Agent . . . . . . . . . . . . . . . . 5 + 1.6. Deleting specific key from the Agent . . . . . . . . . . . . 5 + 1.7. Listing the Keys that the Agent Can Use . . . . . . . . . . 6 +2. Performing Private Key Operations . . . . . . . . . . . . . . . 6 + 2.1. Signing . . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 2.2. Decrypting . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 2.3. Secure Shell Challenge-Response Authentication . . . . . . . 7 +3. Administrative Messages . . . . . . . . . . . . . . . . . . . . 7 + 3.1. Locking and unlocking the agent . . . . . . . . . . . . . . 8 + 3.2. Miscellaneous Agent Commands . . . . . . . . . . . . . . . . 8 +4. Agent Forwarding With Secure Shell . . . . . . . . . . . . . . . 9 + 4.1. Requesting Agent Forwarding . . . . . . . . . . . . . . . . 9 + 4.2. Agent Forwarding Channels . . . . . . . . . . . . . . . . . 9 +5. Security Considerations . . . . . . . . . . . . . . . . . . . . 9 +6. Intellectual Property . . . . . . . . . . . . . . . . . . . . . 10 +7. Additional Information . . . . . . . . . . . . . . . . . . . . . 10 +8. References . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 +9. Address of Authors . . . . . . . . . . . . . . . . . . . . . . . 10 + + + +1. Authentication Agent Protocol + +The authentication agent is a piece of software that runs in a user's +local workstation, laptop, or other trusted device. It is used to +implement single sign-on. It holds the user's private keys in its own +storage, and can perform requested operations using the private key. It +allows the keys to be kept on a smartcard or other special hardware that +can perform cryptographic operations. + +The authentication agent protocol is used to communicate between the +authentication agent and clients wanting to authenticate something or +wanting to perform private key operations. + +The actual communication between the client and the agent happens using +a machine-dependent trusted communications channel. This channel would +typically be a local socket, named pipe, or some kind of secure +messaging system that works inside the local machine. + +The protocol works by the client sending requests to the agent, and the +agent responding to these requests. + +1.1. Packet Format + +All messages passed to/from the authentication agent have the following +format: + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 2] + +INTERNET-DRAFT 20 November, 2002 + + uint32 length + byte type + data[length -1] data payload + +The following packet types are currently defined: + + /* Messages sent by the client. */ + #define SSH_AGENT_REQUEST_VERSION 1 + #define SSH_AGENT_ADD_KEY 202 + #define SSH_AGENT_DELETE_ALL_KEYS 203 + #define SSH_AGENT_LIST_KEYS 204 + #define SSH_AGENT_PRIVATE_KEY_OP 205 + #define SSH_AGENT_FORWARDING_NOTICE 206 + #define SSH_AGENT_DELETE_KEY 207 + #define SSH_AGENT_LOCK 208 + #define SSH_AGENT_UNLOCK 209 + #define SSH_AGENT_PING 212 + #define SSH_AGENT_RANDOM 213 + + /* Messages sent by the agent. */ + #define SSH_AGENT_SUCCESS 101 + #define SSH_AGENT_FAILURE 102 + #define SSH_AGENT_VERSION_RESPONSE 103 + #define SSH_AGENT_KEY_LIST 104 + #define SSH_AGENT_OPERATION_COMPLETE 105 + #define SSH_AGENT_RANDOM_DATA 106 + #define SSH_AGENT_ALIVE 150 + +1.2. Forwarding Notices + +If the agent connection is forwarded through intermediate hosts (using +the SSH Connection Protocol agent forwarding feature (described in +Section ``Agent Forwarding With Secure Shell'' of this document), or +some other means), each intermediate node (Secure Shell client) should +insert the following message into the agent channel before forwarding +any other messages. The real agent will then receive these messages in +sequence the nearest node first, and can determine whether the +connection is from a local machine and if not, can log the path where +the connection came from. These messages must be wrapped in the +appropriate header. + + byte SSH_AGENT_FORWARDING_NOTICE + string remote host name (as typed by the user, preferably) + string remote host ip + uint32 remote host port + +1.3. Requesting Version Number + +When the client opens a connection, it must send the following message +to the server. This must be the first message sent. The real agent +will receive this after zero or more forwarding notice messages. + byte SSH_AGENT_REQUEST_VERSION + string version string of the application sending the request + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 3] + +INTERNET-DRAFT 20 November, 2002 + + (optional) + +If the agent follows this protocol, it will respond with + + byte SSH_AGENT_VERSION_RESPONSE + uint32 version number, 2 for this protocol + +If the version number request is ever sent to the Secure Shell 1.x +agent, it will interpret it as a request to list identities. It will +then respond with a message whose first byte is 2. This can be used to +determine the version of the agent if compatibility with Secure Shell +1.x is desired. + +If the version string query arrives without trailing string identifying +the client software version, it can be translated list identities +request sent by Secure Shell 1.x and handled accordingly. If agent +software does not support the agent protocol of Secure Shell 1.x, it MAY +also interpret this query as valid SSH_AGENT_REQUEST_VERSION packet. + +1.4. Adding Keys to the Agent + +The client can add a new private key to the agent with the following +message. + + byte SSH_AGENT_ADD_KEY + string private key blob with empty passphrase + string public key and/or certificates for it + string description of the key + ... 0, 1 or several constraints follow + +All constraints are pairs of following format: + + byte SSH_AGENT_CONSTRAINT_* + variable argument for the constraint + +The type of the argument is dependent on the constraint type. Following +constraint types are currently defined: + + /* Constraints 50-99 have a uint32 argument */ + + /* Argument is uint32 defining key expiration time-out in + seconds. After this timeout expires, the key can't be used. + 0 == no timeout */ + #define SSH_AGENT_CONSTRAINT_TIMEOUT 50 + + /* Argument is uint32 defining the number of operations that can + be performed with this key. 0xffffffff == no limit */ + #define SSH_AGENT_CONSTRAINT_USE_LIMIT 51 + + /* Argument is uint32 defining the number of forwarding steps that + this key can be forwarded. 0xffffffff == no limit */ + #define SSH_AGENT_CONSTRAINT_FORWARDING_STEPS 52 + + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 4] + +INTERNET-DRAFT 20 November, 2002 + + /* Constraints 100-149 have a string argument */ + + /* Argument is string defining the allowed forwarding steps for + this key. XXX define this. */ + #define SSH_AGENT_CONSTRAINT_FORWARDING_PATH 100 + + /* Constraints 150-199 have a boolean argument */ + + /* Argument is a boolean telling whether the key can be used + in Secure Shell 1.x compatibility operations. */ + + #define SSH_AGENT_CONSTRAINT_SSH1_COMPAT 150 + + /* Argument is a boolean telling whether operations performed + with this key should be confirmed interactively by the user + or not. */ + #define SSH_AGENT_CONSTRAINT_NEED_USER_VERIFICATION 151 + +Message can contain zero, one or multiple constraints. + +If the operation is successful, the agent will respond with the +following message. + + byte SSH_AGENT_SUCCESS + +If the operation fails for some reason, the following message will be +returned instead. + + byte SSH_AGENT_FAILURE + uint32 error code + +The error code is one of the following: + + #define SSH_AGENT_ERROR_TIMEOUT 1 + #define SSH_AGENT_ERROR_KEY_NOT_FOUND 2 + #define SSH_AGENT_ERROR_DECRYPT_FAILED 3 + #define SSH_AGENT_ERROR_SIZE_ERROR 4 + #define SSH_AGENT_ERROR_KEY_NOT_SUITABLE 5 + #define SSH_AGENT_ERROR_DENIED 6 + #define SSH_AGENT_ERROR_FAILURE 7 + #define SSH_AGENT_ERROR_UNSUPPORTED_OP 8 + +1.5. Deleting Keys from the Agent + +All keys that are in possession of the agent can be deleted with the +following message. (The client is allowed to ignore this for some keys +if desired.) + + byte SSH_AGENT_DELETE_ALL_KEYS + +The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE. + + + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 5] + +INTERNET-DRAFT 20 November, 2002 + +1.6. Deleting specific key from the Agent + +The client can delete a specific key with given public key with +following message. + + byte SSH_AGENT_DELETE_KEY + string public key and/or certificates for it + string description of the key + +The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE. + +1.7. Listing the Keys that the Agent Can Use + +The following message requests a list of all keys that the agent can +use. + + byte SSH_AGENT_LIST_KEYS + +The agent will respond with the following message. + + byte SSH_AGENT_KEY_LIST + uint32 number_of_keys + repeats number_of_keys times: + string public key blob or certificates + string description + +2. Performing Private Key Operations + +The real purpose of the agent is to perform private key operations. +Such operations are performed with the following message. + + byte SSH_AGENT_PRIVATE_KEY_OP + string operation name + string key or certificates, as returned in SSH_AGENT_KEY_LIST + ... operation-specific data follows + +The operation to be performed is identified by a name (string). Custom +operations can be added by suffixing the operation name by the fully +qualified domain name of the person/organization adding the new +operation. + +When the operation is complete, the agent will respond with either +SSH_AGENT_FAILURE or with the following message if the operation is +successful: + + byte SSH_AGENT_OPERATION_COMPLETE + string resulting data + +If an operation is attempted that is not supported by the agent, the +agent will respond with SSH_AGENT_FAILURE with error code set to +SSH_AGENT_ERROR_UNSUPPORTED_OP. + +The standard operations are defined below. + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 6] + +INTERNET-DRAFT 20 November, 2002 + +2.1. Signing + +The agent can be used to create a digital signature using a key held by +the agent. The operation name is "sign", and data in is a hash +(suitable for the key) that is to be signed. This normally performs the +raw private key operation, without hashing data first. The resulting +data will be a binary representation of the output of the private key +operation. The exact details of the operations to be performed depend +on the key being used. + +The operation-specific data has the following format: + + string data to be signed + +Alternatively, it is possible to give the actual data to be signed to +the agent. This is done using the operation "hash-and-sign". This is +otherwise equal, but performs key-dependent hashing before signing. + +If the requested operation is not legal for the key, SSH_AGENT_FAILURE +will be returned with error code set to +SSH_AGENT_ERROR_KEY_NOT_SUITABLE. + +2.2. Decrypting + +The agent can be used to decrypt a public key encrypted message with the +operation "decrypt". This takes in raw public-key encrypted data, and +returns the resulting decrypted data. + +This may also fail. If the requested operation is not legal for the +key, error code is set to SSH_AGENT_ERROR_KEY_NOT_SUITABLE. + +The operation-specific data has the following format: + + string data to be decrypted + +2.3. Secure Shell Challenge-Response Authentication + +Performs Secure Shell challenge-response authentication. This operation +has the name "ssh1-challenge-response". + +This operation works by first decrypting the challenge, then computing +MD5 of the concatenation of the decrypted challenge and the session id +(in this order), and returns the resulting 16 byte hash. The operation- +specific data is in the following format: + + string challenge encrypted using the public key + string session id + +Normally, the length of the challenge before encryption will be 32 bytes +and the length of the session id 16 bytes. The length of the encrypted +challenge depends on the key and algorithm used. + + + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 7] + +INTERNET-DRAFT 20 November, 2002 + +3. Administrative Messages + +There are also a number of messages that are only used to administer the +agent. These might e.g. be used by a user interface for the agent. The +agent should only allow these messages from local connection (i.e., if +no forwarding notice messages were received before the version number +request). + +3.1. Locking and unlocking the agent + +The agent can be temporarily locked by message: + + byte SSH_AGENT_LOCK + string locking password + +The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE. +Particularily SSH_AGENT_FAILURE is sent, if agent is already locked. +After this message, agent responds to all commands with +SSH_AGENT_FAILURE until it receives a following command. + + byte SSH_AGENT_UNLOCK + string locking password + +The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE. +Particularily SSH_AGENT_FAILURE is sent, if agent is not locked or if +the submitted password does not match with one given with SSH_AGENT_LOCK +message. + +3.2. Miscellaneous Agent Commands + + byte SSH_AGENT_PING + ... arbitrary padding data + +Any agent or client receiving this message, should respond with + + byte SSH_AGENT_ALIVE + ... padding data from the SSH_AGENT_PING request + +where the padding data is identical to the data sent with +SSH_AGENT_PING. + + byte SSH_AGENT_RANDOM + uint32 the length of the requested random buffer + +Client can request random data from the agent by this message. Agent +responds either with SSH_AGENT_RANDOM_DATA or SSH_AGENT_FAILURE message. + + byte SSH_AGENT_RANDOM_DATA + string random data + +This message is a successful response to SSH_AGENT_RANDOM message. +Message contains the random string of requested length. + + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 8] + +INTERNET-DRAFT 20 November, 2002 + +4. Agent Forwarding With Secure Shell + +The agent connection is typically forwarded over a Secure Shell +connection. This requires small additions to the SSH Connection Protocol +[SSH-CONN]. + +4.1. Requesting Agent Forwarding + +Agent forwarding may be requested for a session by sending + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "auth-agent-req" + boolean want reply + +This will, on success, create an agent listener to the remote end. + +4.2. Agent Forwarding Channels + +When a connection comes to the forwarded agent listener, a channel is +opened to forward the connection to the other side. + + byte SSH_MSG_CHANNEL_OPEN + string "auth-agent" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + +Implementations MUST reject these messages unless they have previously +requested agent forwarding. + +Forwarded agent channels are independent of any sessions, and closing a +session channel does not in any way imply that forwarded connections +should be closed. + +5. Security Considerations + +The authentication agent is used to control security-sensitive +operations, and is used to implement single sign-on. + +Anyone with access to the authentication agent can perform private key +operations with the agent. This is a power equivalent to possession of +the private key as long as the connection to the key is maintained. It +is not possible to retrieve the key from the agent. + +It is recommended that agent implementations allow and perform some form +of logging and access control. This access control may utilize +information about the path through which the connection was received (as +collected with SSH_AGENT_FORWARDING_NOTICE messages; however, the path +is reliable only up to and including the first unreliable machine.). +Implementations should also allow restricting the operations that can be +performed with keys - e.g., limiting them to challenge-response only. + + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 9] + +INTERNET-DRAFT 20 November, 2002 + +One should note that a local superuser will be able to obtain access to +agents running on the local machine. This cannot be prevented; in most +operating systems, a user with sufficient privileges will be able to +read the keys from the physical memory. + +The authentication agent should not be run or forwarded to machine whose +integrity is not trusted, as security on such machines might be +compromised and might allow an attacker to obtain unauthorized access to +the agent. + +6. Intellectual Property + +The IETF takes no position regarding the validity or scope of any +intellectual property or other rights that might be claimed to pertain +to the implementation or use of the technology described in this +document or the extent to which any license under such rights might or +might not be available; neither does it represent that it has made any +effort to identify any such rights. Information on the IETF's +procedures with respect to rights in standards-track and standards- +related documentation can be found in BCP-11. Copies of claims of +rights made available for publication and any assurances of licenses to +be made available, or the result of an attempt made to obtain a general +license or permission for the use of such proprietary rights by +implementers or users of this specification can be obtained from the +IETF Secretariat. + +The IETF has been notified of intellectual property rights claimed in +regard to some or all of the specification contained in this document. +For more information consult the online list of claimed rights. + +7. Additional Information + +The current document editor is: Sami Lehtinen . Comments +on this Internet-Draft should be sent to the IETF SECSH working group, +details at: http://ietf.org/html.charters/secsh-charter.html + +8. References + +[SECSH-CONNECT] Ylonen, T., et al: "Secure Shell Connection Protocol", +Internet-Draft, draft-ietf-secsh-connect-16.txt + +9. Address of Authors + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + FIN-00100 HELSINKI + Finland + E-mail: ylo@ssh.com + + Timo J. Rinne + SSH Communications Security Corp + Fredrikinkatu 42 + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 10] + +INTERNET-DRAFT 20 November, 2002 + + FIN-00100 HELSINKI + Finland + E-mail: tri@ssh.com + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + FIN-00100 HELSINKI + Finland + E-mail: sjl@ssh.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 11] diff --git a/doc/draft-ietf-secsh-architecture-14.txt b/doc/draft-ietf-secsh-architecture-14.txt new file mode 100644 index 00000000..9a7c4082 --- /dev/null +++ b/doc/draft-ietf-secsh-architecture-14.txt @@ -0,0 +1,1736 @@ + + +Network Working Group T. Ylonen +Internet-Draft T. Kivinen +Expires: January 12, 2004 SSH Communications Security Corp + M. Saarinen + University of Jyvaskyla + T. Rinne + S. Lehtinen + SSH Communications Security Corp + July 14, 2003 + + + SSH Protocol Architecture + draft-ietf-secsh-architecture-14.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on January 12, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. This document describes the + architecture of the SSH protocol, as well as the notation and + terminology used in SSH protocol documents. It also discusses the + SSH algorithm naming system that allows local extensions. The SSH + + + +Ylonen, et. al. Expires January 12, 2004 [Page 1] + +Internet-Draft SSH Protocol Architecture July 2003 + + + protocol consists of three major components: The Transport Layer + Protocol provides server authentication, confidentiality, and + integrity with perfect forward secrecy. The User Authentication + Protocol authenticates the client to the server. The Connection + Protocol multiplexes the encrypted tunnel into several logical + channels. Details of these protocols are described in separate + documents. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. Specification of Requirements . . . . . . . . . . . . . . . 4 + 3. Architecture . . . . . . . . . . . . . . . . . . . . . . . . 4 + 3.1 Host Keys . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 3.2 Extensibility . . . . . . . . . . . . . . . . . . . . . . . 6 + 3.3 Policy Issues . . . . . . . . . . . . . . . . . . . . . . . 6 + 3.4 Security Properties . . . . . . . . . . . . . . . . . . . . 7 + 3.5 Packet Size and Overhead . . . . . . . . . . . . . . . . . . 7 + 3.6 Localization and Character Set Support . . . . . . . . . . . 8 + 4. Data Type Representations Used in the SSH Protocols . . . . 9 + 5. Algorithm Naming . . . . . . . . . . . . . . . . . . . . . . 11 + 6. Message Numbers . . . . . . . . . . . . . . . . . . . . . . 12 + 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . 12 + 8. Security Considerations . . . . . . . . . . . . . . . . . . 13 + 8.1 Pseudo-Random Number Generation . . . . . . . . . . . . . . 13 + 8.2 Transport . . . . . . . . . . . . . . . . . . . . . . . . . 14 + 8.2.1 Confidentiality . . . . . . . . . . . . . . . . . . . . . . 14 + 8.2.2 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 17 + 8.2.3 Replay . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 + 8.2.4 Man-in-the-middle . . . . . . . . . . . . . . . . . . . . . 18 + 8.2.5 Denial-of-service . . . . . . . . . . . . . . . . . . . . . 20 + 8.2.6 Covert Channels . . . . . . . . . . . . . . . . . . . . . . 21 + 8.2.7 Forward Secrecy . . . . . . . . . . . . . . . . . . . . . . 21 + 8.3 Authentication Protocol . . . . . . . . . . . . . . . . . . 21 + 8.3.1 Weak Transport . . . . . . . . . . . . . . . . . . . . . . . 22 + 8.3.2 Debug messages . . . . . . . . . . . . . . . . . . . . . . . 22 + 8.3.3 Local security policy . . . . . . . . . . . . . . . . . . . 23 + 8.3.4 Public key authentication . . . . . . . . . . . . . . . . . 23 + 8.3.5 Password authentication . . . . . . . . . . . . . . . . . . 24 + 8.3.6 Host based authentication . . . . . . . . . . . . . . . . . 24 + 8.4 Connection protocol . . . . . . . . . . . . . . . . . . . . 24 + 8.4.1 End point security . . . . . . . . . . . . . . . . . . . . . 24 + 8.4.2 Proxy forwarding . . . . . . . . . . . . . . . . . . . . . . 24 + 8.4.3 X11 forwarding . . . . . . . . . . . . . . . . . . . . . . . 25 + 9. Intellectual Property . . . . . . . . . . . . . . . . . . . 25 + 10. Additional Information . . . . . . . . . . . . . . . . . . . 26 + References . . . . . . . . . . . . . . . . . . . . . . . . . 26 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 29 + + + +Ylonen, et. al. Expires January 12, 2004 [Page 2] + +Internet-Draft SSH Protocol Architecture July 2003 + + + Full Copyright Statement . . . . . . . . . . . . . . . . . . 31 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 3] + +Internet-Draft SSH Protocol Architecture July 2003 + + + 1. Introduction + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. It consists of three major + components: + o The Transport Layer Protocol [SSH-TRANS] provides server + authentication, confidentiality, and integrity. It may + optionally also provide compression. The transport layer will + typically be run over a TCP/IP connection, but might also be + used on top of any other reliable data stream. + o The User Authentication Protocol [SSH-USERAUTH] authenticates + the client-side user to the server. It runs over the transport + layer protocol. + o The Connection Protocol [SSH-CONNECT] multiplexes the encrypted + tunnel into several logical channels. It runs over the user + authentication protocol. + + The client sends a service request once a secure transport layer + connection has been established. A second service request is sent + after user authentication is complete. This allows new protocols + to be defined and coexist with the protocols listed above. + + The connection protocol provides channels that can be used for a + wide range of purposes. Standard methods are provided for setting + up secure interactive shell sessions and for forwarding + ("tunneling") arbitrary TCP/IP ports and X11 connections. + + 2. Specification of Requirements + + All documents related to the SSH protocols shall use the keywords + "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" to describe + requirements. They are to be interpreted as described in [RFC- + 2119]. + + 3. Architecture + + 3.1 Host Keys + + Each server host SHOULD have a host key. Hosts MAY have multiple + host keys using multiple different algorithms. Multiple hosts MAY + share the same host key. If a host has keys at all, it MUST have + at least one key using each REQUIRED public key algorithm + (currently DSS [FIPS-186]). + + The server host key is used during key exchange to verify that the + client is really talking to the correct server. For this to be + possible, the client must have a priori knowledge of the server's + + + +Ylonen, et. al. Expires January 12, 2004 [Page 4] + +Internet-Draft SSH Protocol Architecture July 2003 + + + public host key. + + Two different trust models can be used: + o The client has a local database that associates each host name + (as typed by the user) with the corresponding public host key. + This method requires no centrally administered infrastructure, + and no third-party coordination. The downside is that the + database of name-to-key associations may become burdensome to + maintain. + o The host name-to-key association is certified by some trusted + certification authority. The client only knows the CA root + key, and can verify the validity of all host keys certified by + accepted CAs. + + The second alternative eases the maintenance problem, since + ideally only a single CA key needs to be securely stored on the + client. On the other hand, each host key must be appropriately + certified by a central authority before authorization is + possible. Also, a lot of trust is placed on the central + infrastructure. + + The protocol provides the option that the server name - host key + association is not checked when connecting to the host for the + first time. This allows communication without prior communication + of host keys or certification. The connection still provides + protection against passive listening; however, it becomes + vulnerable to active man-in-the-middle attacks. Implementations + SHOULD NOT normally allow such connections by default, as they + pose a potential security problem. However, as there is no widely + deployed key infrastructure available on the Internet yet, this + option makes the protocol much more usable during the transition + time until such an infrastructure emerges, while still providing a + much higher level of security than that offered by older solutions + (e.g. telnet [RFC-854] and rlogin [RFC-1282]). + + Implementations SHOULD try to make the best effort to check host + keys. An example of a possible strategy is to only accept a host + key without checking the first time a host is connected, save the + key in a local database, and compare against that key on all + future connections to that host. + + Implementations MAY provide additional methods for verifying the + correctness of host keys, e.g. a hexadecimal fingerprint derived + from the SHA-1 hash of the public key. Such fingerprints can + easily be verified by using telephone or other external + communication channels. + + All implementations SHOULD provide an option to not accept host + + + +Ylonen, et. al. Expires January 12, 2004 [Page 5] + +Internet-Draft SSH Protocol Architecture July 2003 + + + keys that cannot be verified. + + We believe that ease of use is critical to end-user acceptance of + security solutions, and no improvement in security is gained if + the new solutions are not used. Thus, providing the option not to + check the server host key is believed to improve the overall + security of the Internet, even though it reduces the security of + the protocol in configurations where it is allowed. + + 3.2 Extensibility + + We believe that the protocol will evolve over time, and some + organizations will want to use their own encryption, + authentication and/or key exchange methods. Central registration + of all extensions is cumbersome, especially for experimental or + classified features. On the other hand, having no central + registration leads to conflicts in method identifiers, making + interoperability difficult. + + We have chosen to identify algorithms, methods, formats, and + extension protocols with textual names that are of a specific + format. DNS names are used to create local namespaces where + experimental or classified extensions can be defined without fear + of conflicts with other implementations. + + One design goal has been to keep the base protocol as simple as + possible, and to require as few algorithms as possible. However, + all implementations MUST support a minimal set of algorithms to + ensure interoperability (this does not imply that the local policy + on all hosts would necessary allow these algorithms). The + mandatory algorithms are specified in the relevant protocol + documents. + + Additional algorithms, methods, formats, and extension protocols + can be defined in separate drafts. See Section Algorithm Naming + (Section 5) for more information. + + 3.3 Policy Issues + + The protocol allows full negotiation of encryption, integrity, key + exchange, compression, and public key algorithms and formats. + Encryption, integrity, public key, and compression algorithms can + be different for each direction. + + The following policy issues SHOULD be addressed in the + configuration mechanisms of each implementation: + o Encryption, integrity, and compression algorithms, separately + for each direction. The policy MUST specify which is the + + + +Ylonen, et. al. Expires January 12, 2004 [Page 6] + +Internet-Draft SSH Protocol Architecture July 2003 + + + preferred algorithm (e.g. the first algorithm listed in each + category). + o Public key algorithms and key exchange method to be used for + host authentication. The existence of trusted host keys for + different public key algorithms also affects this choice. + o The authentication methods that are to be required by the + server for each user. The server's policy MAY require multiple + authentication for some or all users. The required algorithms + MAY depend on the location where the user is trying to log in + from. + o The operations that the user is allowed to perform using the + connection protocol. Some issues are related to security; for + example, the policy SHOULD NOT allow the server to start + sessions or run commands on the client machine, and MUST NOT + allow connections to the authentication agent unless forwarding + such connections has been requested. Other issues, such as + which TCP/IP ports can be forwarded and by whom, are clearly + issues of local policy. Many of these issues may involve + traversing or bypassing firewalls, and are interrelated with + the local security policy. + + 3.4 Security Properties + + The primary goal of the SSH protocol is improved security on the + Internet. It attempts to do this in a way that is easy to deploy, + even at the cost of absolute security. + o All encryption, integrity, and public key algorithms used are + well-known, well-established algorithms. + o All algorithms are used with cryptographically sound key sizes + that are believed to provide protection against even the + strongest cryptanalytic attacks for decades. + o All algorithms are negotiated, and in case some algorithm is + broken, it is easy to switch to some other algorithm without + modifying the base protocol. + + Specific concessions were made to make wide-spread fast deployment + easier. The particular case where this comes up is verifying that + the server host key really belongs to the desired host; the + protocol allows the verification to be left out (but this is NOT + RECOMMENDED). This is believed to significantly improve usability + in the short term, until widespread Internet public key + infrastructures emerge. + + 3.5 Packet Size and Overhead + + Some readers will worry about the increase in packet size due to + new headers, padding, and MAC. The minimum packet size is in the + order of 28 bytes (depending on negotiated algorithms). The + + + +Ylonen, et. al. Expires January 12, 2004 [Page 7] + +Internet-Draft SSH Protocol Architecture July 2003 + + + increase is negligible for large packets, but very significant for + one-byte packets (telnet-type sessions). There are, however, + several factors that make this a non-issue in almost all cases: + o The minimum size of a TCP/IP header is 32 bytes. Thus, the + increase is actually from 33 to 51 bytes (roughly). + o The minimum size of the data field of an Ethernet packet is 46 + bytes [RFC-894]. Thus, the increase is no more than 5 bytes. + When Ethernet headers are considered, the increase is less than + 10 percent. + o The total fraction of telnet-type data in the Internet is + negligible, even with increased packet sizes. + + The only environment where the packet size increase is likely to + have a significant effect is PPP [RFC-1134] over slow modem lines + (PPP compresses the TCP/IP headers, emphasizing the increase in + packet size). However, with modern modems, the time needed to + transfer is in the order of 2 milliseconds, which is a lot faster + than people can type. + + There are also issues related to the maximum packet size. To + minimize delays in screen updates, one does not want excessively + large packets for interactive sessions. The maximum packet size + is negotiated separately for each channel. + + 3.6 Localization and Character Set Support + + For the most part, the SSH protocols do not directly pass text + that would be displayed to the user. However, there are some + places where such data might be passed. When applicable, the + character set for the data MUST be explicitly specified. In most + places, ISO 10646 with UTF-8 encoding is used [RFC-2279]. When + applicable, a field is also provided for a language tag [RFC- + 1766]. + + One big issue is the character set of the interactive session. + There is no clear solution, as different applications may display + data in different formats. Different types of terminal emulation + may also be employed in the client, and the character set to be + used is effectively determined by the terminal emulation. Thus, + no place is provided for directly specifying the character set or + encoding for terminal session data. However, the terminal + emulation type (e.g. "vt100") is transmitted to the remote site, + and it implicitly specifies the character set and encoding. + Applications typically use the terminal type to determine what + character set they use, or the character set is determined using + some external means. The terminal emulation may also allow + configuring the default character set. In any case, the character + set for the terminal session is considered primarily a client + + + +Ylonen, et. al. Expires January 12, 2004 [Page 8] + +Internet-Draft SSH Protocol Architecture July 2003 + + + local issue. + + Internal names used to identify algorithms or protocols are + normally never displayed to users, and must be in US-ASCII. + + The client and server user names are inherently constrained by + what the server is prepared to accept. They might, however, + occasionally be displayed in logs, reports, etc. They MUST be + encoded using ISO 10646 UTF-8, but other encodings may be required + in some cases. It is up to the server to decide how to map user + names to accepted user names. Straight bit-wise binary comparison + is RECOMMENDED. + + For localization purposes, the protocol attempts to minimize the + number of textual messages transmitted. When present, such + messages typically relate to errors, debugging information, or + some externally configured data. For data that is normally + displayed, it SHOULD be possible to fetch a localized message + instead of the transmitted message by using a numerical code. The + remaining messages SHOULD be configurable. + + 4. Data Type Representations Used in the SSH Protocols + byte + + A byte represents an arbitrary 8-bit value (octet) [RFC-1700]. + Fixed length data is sometimes represented as an array of + bytes, written byte[n], where n is the number of bytes in the + array. + + boolean + + A boolean value is stored as a single byte. The value 0 + represents FALSE, and the value 1 represents TRUE. All non- + zero values MUST be interpreted as TRUE; however, applications + MUST NOT store values other than 0 and 1. + + uint32 + + Represents a 32-bit unsigned integer. Stored as four bytes in + the order of decreasing significance (network byte order). For + example, the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4 + aa. + + uint64 + + Represents a 64-bit unsigned integer. Stored as eight bytes in + the order of decreasing significance (network byte order). + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 9] + +Internet-Draft SSH Protocol Architecture July 2003 + + + string + + Arbitrary length binary string. Strings are allowed to contain + arbitrary binary data, including null characters and 8-bit + characters. They are stored as a uint32 containing its length + (number of bytes that follow) and zero (= empty string) or more + bytes that are the value of the string. Terminating null + characters are not used. + + Strings are also used to store text. In that case, US-ASCII is + used for internal names, and ISO-10646 UTF-8 for text that + might be displayed to the user. The terminating null character + SHOULD NOT normally be stored in the string. + + For example, the US-ASCII string "testing" is represented as 00 + 00 00 07 t e s t i n g. The UTF8 mapping does not alter the + encoding of US-ASCII characters. + + mpint + + Represents multiple precision integers in two's complement + format, stored as a string, 8 bits per byte, MSB first. + Negative numbers have the value 1 as the most significant bit + of the first byte of the data partition. If the most + significant bit would be set for a positive number, the number + MUST be preceded by a zero byte. Unnecessary leading bytes + with the value 0 or 255 MUST NOT be included. The value zero + MUST be stored as a string with zero bytes of data. + + By convention, a number that is used in modular computations in + Z_n SHOULD be represented in the range 0 <= x < n. + + Examples: + value (hex) representation (hex) + --------------------------------------------------------------- + 0 00 00 00 00 + 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7 + 80 00 00 00 02 00 80 + -1234 00 00 00 02 ed cc + -deadbeef 00 00 00 05 ff 21 52 41 11 + + + + name-list + + A string containing a comma separated list of names. A name + list is represented as a uint32 containing its length (number + of bytes that follow) followed by a comma-separated list of + + + +Ylonen, et. al. Expires January 12, 2004 [Page 10] + +Internet-Draft SSH Protocol Architecture July 2003 + + + zero or more names. A name MUST be non-zero length, and it + MUST NOT contain a comma (','). Context may impose additional + restrictions on the names; for example, the names in a list may + have to be valid algorithm identifier (see Algorithm Naming + below), or [RFC-1766] language tags. The order of the names in + a list may or may not be significant, also depending on the + context where the list is is used. Terminating NUL characters + are not used, neither for the individual names, nor for the + list as a whole. + + Examples: + value representation (hex) + --------------------------------------- + (), the empty list 00 00 00 00 + ("zlib") 00 00 00 04 7a 6c 69 62 + ("zlib", "none") 00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65 + + + + + 5. Algorithm Naming + + The SSH protocols refer to particular hash, encryption, integrity, + compression, and key exchange algorithms or protocols by names. + There are some standard algorithms that all implementations MUST + support. There are also algorithms that are defined in the + protocol specification but are OPTIONAL. Furthermore, it is + expected that some organizations will want to use their own + algorithms. + + In this protocol, all algorithm identifiers MUST be printable US- + ASCII non-empty strings no longer than 64 characters. Names MUST + be case-sensitive. + + There are two formats for algorithm names: + o Names that do not contain an at-sign (@) are reserved to be + assigned by IETF consensus (RFCs). Examples include `3des- + cbc', `sha-1', `hmac-sha1', and `zlib' (the quotes are not part + of the name). Names of this format MUST NOT be used without + first registering them. Registered names MUST NOT contain an + at-sign (@) or a comma (,). + o Anyone can define additional algorithms by using names in the + format name@domainname, e.g. "ourcipher-cbc@ssh.com". The + format of the part preceding the at sign is not specified; it + MUST consist of US-ASCII characters except at-sign and comma. + The part following the at-sign MUST be a valid fully qualified + internet domain name [RFC-1034] controlled by the person or + organization defining the name. It is up to each domain how it + + + +Ylonen, et. al. Expires January 12, 2004 [Page 11] + +Internet-Draft SSH Protocol Architecture July 2003 + + + manages its local namespace. + + 6. Message Numbers + + SSH packets have message numbers in the range 1 to 255. These + numbers have been allocated as follows: + + + Transport layer protocol: + + 1 to 19 Transport layer generic (e.g. disconnect, ignore, debug, + etc.) + 20 to 29 Algorithm negotiation + 30 to 49 Key exchange method specific (numbers can be reused for + different authentication methods) + + User authentication protocol: + + 50 to 59 User authentication generic + 60 to 79 User authentication method specific (numbers can be + reused for different authentication methods) + + Connection protocol: + + 80 to 89 Connection protocol generic + 90 to 127 Channel related messages + + Reserved for client protocols: + + 128 to 191 Reserved + + Local extensions: + + 192 to 255 Local extensions + + + + 7. IANA Considerations + + Allocation of the following types of names in the SSH protocols is + assigned by IETF consensus: + o encryption algorithm names, + o MAC algorithm names, + o public key algorithm names (public key algorithm also implies + encoding and signature/encryption capability), + o key exchange method names, and + o protocol (service) names. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 12] + +Internet-Draft SSH Protocol Architecture July 2003 + + + These names MUST be printable US-ASCII strings, and MUST NOT + contain the characters at-sign ('@'), comma (','), or whitespace + or control characters (ASCII codes 32 or less). Names are case- + sensitive, and MUST NOT be longer than 64 characters. + + Names with the at-sign ('@') in them are allocated by the owner of + DNS name after the at-sign (hierarchical allocation in [RFC- + 2343]), otherwise the same restrictions as above. + + Each category of names listed above has a separate namespace. + However, using the same name in multiple categories SHOULD be + avoided to minimize confusion. + + Message numbers (see Section Message Numbers (Section 6)) in the + range of 0..191 should be allocated via IETF consensus; message + numbers in the 192..255 range (the "Local extensions" set) are + reserved for private use. + + 8. Security Considerations + + In order to make the entire body of Security Considerations more + accessible, Security Considerations for the transport, + authentication, and connection documents have been gathered here. + + The transport protocol [1] provides a confidential channel over an + insecure network. It performs server host authentication, key + exchange, encryption, and integrity protection. It also derives a + unique session id that may be used by higher-level protocols. + + The authentication protocol [2] provides a suite of mechanisms + which can be used to authenticate the client user to the server. + Individual mechanisms specified in the in authentication protocol + use the session id provided by the transport protocol and/or + depend on the security and integrity guarantees of the transport + protocol. + + The connection protocol [3] specifies a mechanism to multiplex + multiple streams [channels] of data over the confidential and + authenticated transport. It also specifies channels for accessing + an interactive shell, for 'proxy-forwarding' various external + protocols over the secure transport (including arbitrary TCP/IP + protocols), and for accessing secure 'subsystems' on the server + host. + + 8.1 Pseudo-Random Number Generation + + This protocol binds each session key to the session by including + random, session specific data in the hash used to produce session + + + +Ylonen, et. al. Expires January 12, 2004 [Page 13] + +Internet-Draft SSH Protocol Architecture July 2003 + + + keys. Special care should be taken to ensure that all of the + random numbers are of good quality. If the random data here + (e.g., DH parameters) are pseudo-random then the pseudo-random + number generator should be cryptographically secure (i.e., its + next output not easily guessed even when knowing all previous + outputs) and, furthermore, proper entropy needs to be added to the + pseudo-random number generator. RFC 1750 [1750] offers + suggestions for sources of random numbers and entropy. + Implementors should note the importance of entropy and the well- + meant, anecdotal warning about the difficulty in properly + implementing pseudo-random number generating functions. + + The amount of entropy available to a given client or server may + sometimes be less than what is required. In this case one must + either resort to pseudo-random number generation regardless of + insufficient entropy or refuse to run the protocol. The latter is + preferable. + + 8.2 Transport + + 8.2.1 Confidentiality + + It is beyond the scope of this document and the Secure Shell + Working Group to analyze or recommend specific ciphers other than + the ones which have been established and accepted within the + industry. At the time of this writing, ciphers commonly in use + include 3DES, ARCFOUR, twofish, serpent and blowfish. AES has + been accepted by The published as a US Federal Information + Processing Standards [FIPS-197] and the cryptographic community as + being acceptable for this purpose as well has accepted AES. As + always, implementors and users should check current literature to + ensure that no recent vulnerabilities have been found in ciphers + used within products. Implementors should also check to see which + ciphers are considered to be relatively stronger than others and + should recommend their use to users over relatively weaker + ciphers. It would be considered good form for an implementation + to politely and unobtrusively notify a user that a stronger cipher + is available and should be used when a weaker one is actively + chosen. + + The "none" cipher is provided for debugging and SHOULD NOT be used + except for that purpose. It's cryptographic properties are + sufficiently described in RFC 2410, which will show that its use + does not meet the intent of this protocol. + + The relative merits of these and other ciphers may also be found + in current literature. Two references that may provide + information on the subject are [SCHNEIER] and + + + +Ylonen, et. al. Expires January 12, 2004 [Page 14] + +Internet-Draft SSH Protocol Architecture July 2003 + + + [KAUFMAN,PERLMAN,SPECINER]. Both of these describe the CBC mode + of operation of certain ciphers and the weakness of this scheme. + Essentially, this mode is theoretically vulnerable to chosen + cipher-text attacks because of the high predictability of the + start of packet sequence. However, this attack is still deemed + difficult and not considered fully practicable especially if + relatively longer block sizes are used. + + Additionally, another CBC mode attack may be mitigated through the + insertion of packets containing SSH_MSG_IGNORE. Without this + technique, a specific attack may be successful. For this attack + (commonly known as the Rogaway attack + [ROGAWAY],[DAI],[BELLARE,KOHNO,NAMPREMPRE]) to work, the attacker + would need to know the IV of the next block that is going to be + encrypted. In CBC mode that is the output of the encryption of + the previous block. If the attacker does not have any way to see + the packet yet (i.e it is in the internal buffers of the ssh + implementation or even in the kernel) then this attack will not + work. If the last packet has been sent out to the network (i.e + the attacker has access to it) then he can use the attack. + + In the optimal case an implementor would need to add an extra + packet only if the packet has been sent out onto the network and + there are no other packets waiting for transmission. Implementors + may wish to check to see if there are any unsent packets awaiting + transmission, but unfortunately it is not normally easy to obtain + this information from the kernel or buffers. If there are not, + then a packet containing SSH_MSG_IGNORE SHOULD be sent. If a new + packet is added to the stream every time the attacker knows the IV + that is supposed to be used for the next packet, then the attacker + will not be able to guess the correct IV, thus the attack will + never be successfull. + + As an example, consider the following case: + + + Client Server + ------ ------ + TCP(seq=x, len=500) -> + contains Record 1 + + [500 ms passes, no ACK] + + TCP(seq=x, len=1000) -> + contains Records 1,2 + + ACK + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 15] + +Internet-Draft SSH Protocol Architecture July 2003 + + + 1. The Nagle algorithm + TCP retransmits mean that the two + records get coalesced into a single TCP segment + 2. Record 2 is *not* at the beginning of the TCP segment and + never will be, since it gets ACKed. + 3. Yet, the attack is possible because Record 1 has already been + seen. + + As this example indicates, it's totally unsafe to use the + existence of unflushed data in the TCP buffers proper as a guide + to whether you need an empty packet, since when you do the second + write(), the buffers will contain the un-ACKed Record 1. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 16] + +Internet-Draft SSH Protocol Architecture July 2003 + + + On the other hand, it's perfectly safe to have the following + situation: + + + Client Server + ------ ------ + TCP(seq=x, len=500) -> + contains SSH_MSG_IGNORE + + TCP(seq=y, len=500) -> + contains Data + + Provided that the IV for second SSH Record is fixed after the data for + the Data packet is determined -i.e. you do: + read from user + encrypt null packet + encrypt data packet + + + 8.2.2 Data Integrity + + This protocol does allow the Data Integrity mechanism to be + disabled. Implementors SHOULD be wary of exposing this feature + for any purpose other than debugging. Users and administrators + SHOULD be explicitly warned anytime the "none" MAC is enabled. + + So long as the "none" MAC is not used, this protocol provides data + integrity. + + Because MACs use a 32 bit sequence number, they might start to + leak information after 2**32 packets have been sent. However, + following the rekeying recommendations should prevent this attack. + The transport protocol [1] recommends rekeying after one gigabyte + of data, and the smallest possible packet is 16 bytes. Therefore, + rekeying SHOULD happen after 2**28 packets at the very most. + + 8.2.3 Replay + + The use of a MAC other than 'none' provides integrity and + authentication. In addition, the transport protocol provides a + unique session identifier (bound in part to pseudo-random data + that is part of the algorithm and key exchange process) that can + be used by higher level protocols to bind data to a given session + and prevent replay of data from prior sessions. For example, the + authentication protocol uses this to prevent replay of signatures + from previous sessions. Because public key authentication + exchanges are cryptographically bound to the session (i.e., to the + initial key exchange) they cannot be successfully replayed in + + + +Ylonen, et. al. Expires January 12, 2004 [Page 17] + +Internet-Draft SSH Protocol Architecture July 2003 + + + other sessions. Note that the session ID can be made public + without harming the security of the protocol. + + If two session happen to have the same session ID [hash of key + exchanges] then packets from one can be replayed against the + other. It must be stressed that the chances of such an occurrence + are, needless to say, minimal when using modern cryptographic + methods. This is all the more so true when specifying larger hash + function outputs and DH parameters. + + Replay detection using monotonically increasing sequence numbers + as input to the MAC, or HMAC in some cases, is described in RFC + 2085 [2085], RFC 2246 [2246], RFC 2743 [2743], RFC 1964 [1964], + RFC 2025 [2025], and RFC 1510 [1510]. The underlying construct is + discussed in RFC 2104 [2104]. Essentially a different sequence + number in each packet ensures that at least this one input to the + MAC function will be unique and will provide a nonrecurring MAC + output that is not predictable to an attacker. If the session + stays active long enough, however, this sequence number will wrap. + This event may provide an attacker an opportunity to replay a + previously recorded packet with an identical sequence number but + only if the peers have not rekeyed since the transmission of the + first packet with that sequence number. If the peers have + rekeyed, then the replay will be detected as the MAC check will + fail. For this reason, it must be emphasized that peers MUST + rekey before a wrap of the sequence numbers. Naturally, if an + attacker does attempt to replay a captured packet before the peers + have rekeyed, then the receiver of the duplicate packet will not + be able to validate the MAC and it will be discarded. The reason + that the MAC will fail is because the receiver will formulate a + MAC based upon the packet contents, the shared secret, and the + expected sequence number. Since the replayed packet will not be + using that expected sequence number (the sequence number of the + replayed packet will have already been passed by the receiver) + then the calculated MAC will not match the MAC received with the + packet. + + 8.2.4 Man-in-the-middle + + This protocol makes no assumptions nor provisions for an + infrastructure or means for distributing the public keys of hosts. + It is expected that this protocol will sometimes be used without + first verifying the association between the server host key and + the server host name. Such usage is vulnerable to man-in-the- + middle attacks. This section describes this and encourages + administrators and users to understand the importance of verifying + this association before any session is initiated. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 18] + +Internet-Draft SSH Protocol Architecture July 2003 + + + There are three cases of man-in-the-middle attacks to consider. + The first is where an attacker places a device between the client + and the server before the session is initiated. In this case, the + attack device is trying to mimic the legitimate server and will + offer its public key to the client when the client initiates a + session. If it were to offer the public key of the server, then + it would not be able to decrypt or sign the transmissions between + the legitimate server and the client unless it also had access to + the private-key of the host. The attack device will also, + simultaneously to this, initiate a session to the legitimate + server masquerading itself as the client. If the public key of + the server had been securely distributed to the client prior to + that session initiation, the key offered to the client by the + attack device will not match the key stored on the client. In + that case, the user SHOULD be given a warning that the offered + host key does not match the host key cached on the client. As + described in Section 3.1 of [ARCH], the user may be free to accept + the new key and continue the session. It is RECOMMENDED that the + warning provide sufficient information to the user of the client + device so they may make an informed decision. If the user chooses + to continue the session with the stored public-key of the server + (not the public-key offered at the start of the session), then the + session specific data between the attacker and server will be + different between the client-to-attacker session and the attacker- + to-server sessions due to the randomness discussed above. From + this, the attacker will not be able to make this attack work since + the attacker will not be able to correctly sign packets containing + this session specific data from the server since he does not have + the private key of that server. + + The second case that should be considered is similar to the first + case in that it also happens at the time of connection but this + case points out the need for the secure distribution of server + public keys. If the server public keys are not securely + distributed then the client cannot know if it is talking to the + intended server. An attacker may use social engineering + techniques to pass off server keys to unsuspecting users and may + then place a man-in-the-middle attack device between the + legitimate server and the clients. If this is allowed to happen + then the clients will form client-to-attacker sessions and the + attacker will form attacker-to-server sessions and will be able to + monitor and manipulate all of the traffic between the clients and + the legitimate servers. Server administrators are encouraged to + make host key fingerprints available for checking by some means + whose security does not rely on the integrity of the actual host + keys. Possible mechanisms are discussed in Section 3.1 of [SSH- + ARCH] and may also include secured Web pages, physical pieces of + paper, etc. Implementors SHOULD provide recommendations on how + + + +Ylonen, et. al. Expires January 12, 2004 [Page 19] + +Internet-Draft SSH Protocol Architecture July 2003 + + + best to do this with their implementation. Because the protocol + is extensible, future extensions to the protocol may provide + better mechanisms for dealing with the need to know the server's + host key before connecting. For example, making the host key + fingerprint available through a secure DNS lookup, or using + kerberos over gssapi during key exchange to authenticate the + server are possibilities. + + In the third man-in-the-middle case, attackers may attempt to + manipulate packets in transit between peers after the session has + been established. As described in the Replay part of this + section, a successful attack of this nature is very improbable. + As in the Replay section, this reasoning does assume that the MAC + is secure and that it is infeasible to construct inputs to a MAC + algorithm to give a known output. This is discussed in much + greater detail in Section 6 of RFC 2104. If the MAC algorithm has + a vulnerability or is weak enough, then the attacker may be able + to specify certain inputs to yield a known MAC. With that they + may be able to alter the contents of a packet in transit. + Alternatively the attacker may be able to exploit the algorithm + vulnerability or weakness to find the shared secret by reviewing + the MACs from captured packets. In either of those cases, an + attacker could construct a packet or packets that could be + inserted into an SSH stream. To prevent that, implementors are + encouraged to utilize commonly accepted MAC algorithms and + administrators are encouraged to watch current literature and + discussions of cryptography to ensure that they are not using a + MAC algorithm that has a recently found vulnerability or weakness. + + In summary, the use of this protocol without a reliable + association of the binding between a host and its host keys is + inherently insecure and is NOT RECOMMENDED. It may however be + necessary in non-security critical environments, and will still + provide protection against passive attacks. Implementors of + protocols and applications running on top of this protocol should + keep this possibility in mind. + + 8.2.5 Denial-of-service + + This protocol is designed to be used over a reliable transport. + If transmission errors or message manipulation occur, the + connection is closed. The connection SHOULD be re-established if + this occurs. Denial of service attacks of this type ("wire + cutter") are almost impossible to avoid. + + In addition, this protocol is vulnerable to Denial of Service + attacks because an attacker can force the server to go through the + CPU and memory intensive tasks of connection setup and key + + + +Ylonen, et. al. Expires January 12, 2004 [Page 20] + +Internet-Draft SSH Protocol Architecture July 2003 + + + exchange without authenticating. Implementors SHOULD provide + features that make this more difficult. For example, only + allowing connections from a subset of IPs known to have valid + users. + + 8.2.6 Covert Channels + + The protocol was not designed to eliminate covert channels. For + example, the padding, SSH_MSG_IGNORE messages, and several other + places in the protocol can be used to pass covert information, and + the recipient has no reliable way to verify whether such + information is being sent. + + 8.2.7 Forward Secrecy + + It should be noted that the Diffie-Hellman key exchanges may + provide perfect forward secrecy (PFS). PFS is essentially defined + as the cryptographic property of a key-establishment protocol in + which the compromise of a session key or long-term private key + after a given session does not cause the compromise of any earlier + session. [ANSI T1.523-2001] SSHv2 sessions resulting from a key + exchange using diffie-hellman-group1-sha1 are secure even if + private keying/authentication material is later revealed, but not + if the session keys are revealed. So, given this definition of + PFS, SSHv2 does have PFS. It is hoped that all other key exchange + mechanisms proposed and used in the future will also provide PFS. + This property is not commuted to any of the applications or + protocols using SSH as a transport however. The transport layer + of SSH provides confidentiality for password authentication and + other methods that rely on secret data. + + Of course, if the DH private parameters for the client and server + are revealed then the session key is revealed, but these items can + be thrown away after the key exchange completes. It's worth + pointing out that these items should not be allowed to end up on + swap space and that they should be erased from memory as soon as + the key exchange completes. + + 8.3 Authentication Protocol + + The purpose of this protocol is to perform client user + authentication. It assumes that this run over a secure transport + layer protocol, which has already authenticated the server + machine, established an encrypted communications channel, and + computed a unique session identifier for this session. + + Several authentication methods with different security + characteristics are allowed. It is up to the server's local + + + +Ylonen, et. al. Expires January 12, 2004 [Page 21] + +Internet-Draft SSH Protocol Architecture July 2003 + + + policy to decide which methods (or combinations of methods) it is + willing to accept for each user. Authentication is no stronger + than the weakest combination allowed. + + The server may go into a "sleep" period after repeated + unsuccessful authentication attempts to make key search more + difficult for attackers. Care should be taken so that this + doesn't become a self-denial of service vector. + + 8.3.1 Weak Transport + + If the transport layer does not provide confidentiality, + authentication methods that rely on secret data SHOULD be + disabled. If it does not provide strong integrity protection, + requests to change authentication data (e.g. a password change) + SHOULD be disabled to prevent an attacker from modifying the + ciphertext without being noticed, or rendering the new + authentication data unusable (denial of service). + + The assumption as stated above that the Authentication Protocol + only run over a secure transport that has previously authenticated + the server is very important to note. People deploying SSH are + reminded of the consequences of man-in-the-middle attacks if the + client does not have a very strong a priori association of the + server with the host key of that server. Specifically for the + case of the Authentication Protocol the client may form a session + to a man-in-the-middle attack device and divulge user credentials + such as their username and password. Even in the cases of + authentication where no user credentials are divulged, an attacker + may still gain information they shouldn't have by capturing key- + strokes in much the same way that a honeypot works. + + 8.3.2 Debug messages + + Special care should be taken when designing debug messages. These + messages may reveal surprising amounts of information about the + host if not properly designed. Debug messages can be disabled + (during user authentication phase) if high security is required. + Administrators of host machines should make all attempts to + compartmentalize all event notification messages and protect them + from unwarranted observation. Developers should be aware of the + sensitive nature of some of the normal event messages and debug + messages and may want to provide guidance to administrators on + ways to keep this information away from unauthorized people. + Developers should consider minimizing the amount of sensitive + information obtainable by users during the authentication phase in + accordance with the local policies. For this reason, it is + RECOMMENDED that debug messages be initially disabled at the time + + + +Ylonen, et. al. Expires January 12, 2004 [Page 22] + +Internet-Draft SSH Protocol Architecture July 2003 + + + of deployment and require an active decision by an administrator + to allow them to be enabled. It is also RECOMMENDED that a + message expressing this concern be presented to the administrator + of a system when the action is taken to enable debugging messages. + + 8.3.3 Local security policy + + Implementer MUST ensure that the credentials provided validate the + professed user and also MUST ensure that the local policy of the + server permits the user the access requested. In particular, + because of the flexible nature of the SSH connection protocol, it + may not be possible to determine the local security policy, if + any, that should apply at the time of authentication because the + kind of service being requested is not clear at that instant. For + example, local policy might allow a user to access files on the + server, but not start an interactive shell. However, during the + authentication protocol, it is not known whether the user will be + accessing files or attempting to use an interactive shell, or even + both. In any event, where local security policy for the server + host exists, it MUST be applied and enforced correctly. + + Implementors are encouraged to provide a default local policy and + make its parameters known to administrators and users. At the + discretion of the implementors, this default policy may be along + the lines of 'anything goes' where there are no restrictions + placed upon users, or it may be along the lines of 'excessively + restrictive' in which case the administrators will have to + actively make changes to this policy to meet their needs. + Alternatively, it may be some attempt at providing something + practical and immediately useful to the administrators of the + system so they don't have to put in much effort to get SSH + working. Whatever choice is made MUST be applied and enforced as + required above. + + 8.3.4 Public key authentication + + The use of public-key authentication assumes that the client host + has not been compromised. + + This risk can be mitigated by the use of passphrases on private + keys; however, this is not an enforceable policy. The use of + smartcards, or other technology to make passphrases an enforceable + policy is suggested. + + The server could require both password and public-key + authentication, however, this requires the client to expose its + password to the server (see section on password authentication + below.) + + + +Ylonen, et. al. Expires January 12, 2004 [Page 23] + +Internet-Draft SSH Protocol Architecture July 2003 + + + 8.3.5 Password authentication + + The password mechanism as specified in the authentication protocol + assumes that the server has not been compromised. If the server + has been compromised, using password authentication will reveal a + valid username / password combination to the attacker, which may + lead to further compromises. + + This vulnerability can be mitigated by using an alternative form + of authentication. For example, public-key authentication makes + no assumptions about security on the server. + + 8.3.6 Host based authentication + + Host based authentication assumes that the client has not been + compromised. There are no mitigating strategies, other than to + use host based authentication in combination with another + authentication method. + + 8.4 Connection protocol + + 8.4.1 End point security + + End point security is assumed by the connection protocol. If the + server has been compromised, any terminal sessions, port + forwarding, or systems accessed on the host are compromised. + There are no mitigating factors for this. + + If the client end point has been compromised, and the server fails + to stop the attacker at the authentication protocol, all services + exposed (either as subsystems or through forwarding) will be + vulnerable to attack. Implementors SHOULD provide mechanisms for + administrators to control which services are exposed to limit the + vulnerability of other services. + + These controls might include controlling which machines and ports + can be target in 'port-forwarding' operations, which users are + allowed to use interactive shell facilities, or which users are + allowed to use exposed subsystems. + + 8.4.2 Proxy forwarding + + The SSH connection protocol allows for proxy forwarding of other + protocols such as SNMP, POP3, and HTTP. This may be a concern for + network administrators who wish to control the access of certain + applications by users located outside of their physical location. + Essentially, the forwarding of these protocols may violate site + specific security policies as they may be undetectably tunneled + + + +Ylonen, et. al. Expires January 12, 2004 [Page 24] + +Internet-Draft SSH Protocol Architecture July 2003 + + + through a firewall. Implementors SHOULD provide an administrative + mechanism to control the proxy forwarding functionality so that + site specific security policies may be upheld. + + In addition, a reverse proxy forwarding functionality is + available, which again can be used to bypass firewall controls. + + As indicated above, end-point security is assumed during proxy + forwarding operations. Failure of end-point security will + compromise all data passed over proxy forwarding. + + 8.4.3 X11 forwarding + + Another form of proxy forwarding provided by the ssh connection + protocol is the forwarding of the X11 protocol. If end-point + security has been compromised, X11 forwarding may allow attacks + against the X11 server. Users and administrators should, as a + matter of course, use appropriate X11 security mechanisms to + prevent unauthorized use of the X11 server. Implementors, + administrators and users who wish to further explore the security + mechanisms of X11 are invited to read [SCHEIFLER] and analyze + previously reported problems with the interactions between SSH + forwarding and X11 in CERT vulnerabilities VU#363181 and VU#118892 + [CERT]. + + X11 display forwarding with SSH, by itself, is not sufficient to + correct well known problems with X11 security [VENEMA]. However, + X11 display forwarding in SSHv2 (or other, secure protocols), + combined with actual and pseudo-displays which accept connections + only over local IPC mechanisms authorized by permissions or ACLs, + does correct many X11 security problems as long as the "none" MAC + is not used. It is RECOMMENDED that X11 display implementations + default to allowing display opens only over local IPC. It is + RECOMMENDED that SSHv2 server implementations that support X11 + forwarding default to allowing display opens only over local IPC. + On single-user systems it might be reasonable to default to + allowing local display opens over TCP/IP. + + Implementors of the X11 forwarding protocol SHOULD implement the + magic cookie access checking spoofing mechanism as described in + [ssh-connect] as an additional mechanism to prevent unauthorized + use of the proxy. + + 9. Intellectual Property + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described + + + +Ylonen, et. al. Expires January 12, 2004 [Page 25] + +Internet-Draft SSH Protocol Architecture July 2003 + + + in this document or the extent to which any license under such + rights might or might not be available; neither does it represent + that it has made any effort to identify any such rights. + Information on the IETF's procedures with respect to rights in + standards-track and standards-related documentation can be found + in BCP-11. Copies of claims of rights made available for + publication and any assurances of licenses to be made available, + or the result of an attempt made to obtain a general license or + permission for the use of such proprietary rights by implementers + or users of this specification can be obtained from the IETF + Secretariat. + + The IETF has been notified of intellectual property rights claimed + in regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + 10. Additional Information + + The current document editor is: Darren.Moffat@Sun.COM. Comments + on this internet draft should be sent to the IETF SECSH working + group, details at: http://ietf.org/html.charters/secsh- + charter.html + +References + + [FIPS-186] Federal Information Processing + Standards Publication, ., "FIPS PUB + 186, Digital Signature Standard", May + 1994. + + [FIPS-197] National Institue of Standards and + Technology, ., "FIPS 197, + Specification for the Advanced + Encryption Standard", November 2001. + + [ANSI T1.523-2001] American National Standards Insitute, + Inc., "Telecom Glossary 2000", + February 2001. + + [SCHEIFLER] Scheifler, R., "X Window System : The + Complete Reference to Xlib, X + Protocol, Icccm, Xlfd, 3rd edition.", + Digital Press ISBN 1555580882, + Feburary 1992. + + [RFC0854] Postel, J. and J. Reynolds, "Telnet + Protocol Specification", STD 8, RFC + + + +Ylonen, et. al. Expires January 12, 2004 [Page 26] + +Internet-Draft SSH Protocol Architecture July 2003 + + + 854, May 1983. + + [RFC0894] Hornig, C., "Standard for the + transmission of IP datagrams over + Ethernet networks", STD 41, RFC 894, + Apr 1984. + + [RFC1034] Mockapetris, P., "Domain names - + concepts and facilities", STD 13, RFC + 1034, Nov 1987. + + [RFC1134] Perkins, D., "Point-to-Point Protocol: + A proposal for multi-protocol + transmission of datagrams over Point- + to-Point links", RFC 1134, Nov 1989. + + [RFC1282] Kantor, B., "BSD Rlogin", RFC 1282, + December 1991. + + [RFC1510] Kohl, J. and C. Neuman, "The Kerberos + Network Authentication Service (V5)", + RFC 1510, September 1993. + + [RFC1700] Reynolds, J. and J. Postel, "Assigned + Numbers", STD 2, RFC 1700, October + 1994. + + [RFC1750] Eastlake, D., Crocker, S. and J. + Schiller, "Randomness Recommendations + for Security", RFC 1750, December + 1994. + + [RFC1766] Alvestrand, H., "Tags for the + Identification of Languages", RFC + 1766, March 1995. + + [RFC1964] Linn, J., "The Kerberos Version 5 GSS- + API Mechanism", RFC 1964, June 1996. + + [RFC2025] Adams, C., "The Simple Public-Key GSS- + API Mechanism (SPKM)", RFC 2025, + October 1996. + + [RFC2085] Oehler, M. and R. Glenn, "HMAC-MD5 IP + Authentication with Replay + Prevention", RFC 2085, February 1997. + + [RFC2104] Krawczyk, H., Bellare, M. and R. + + + +Ylonen, et. al. Expires January 12, 2004 [Page 27] + +Internet-Draft SSH Protocol Architecture July 2003 + + + Canetti, "HMAC: Keyed-Hashing for + Message Authentication", RFC 2104, + February 1997. + + [RFC2119] Bradner, S., "Key words for use in + RFCs to Indicate Requirement Levels", + BCP 14, RFC 2119, March 1997. + + [RFC2246] Dierks, T. and C. Allen, "The TLS + Protocol Version 1.0", RFC 2246, + January 1999. + + [RFC2279] Yergeau, F., "UTF-8, a transformation + format of ISO 10646", RFC 2279, + January 1998. + + [RFC2410] Glenn, R. and S. Kent, "The NULL + Encryption Algorithm and Its Use With + IPsec", RFC 2410, November 1998. + + [RFC2434] Narten, T. and H. Alvestrand, + "Guidelines for Writing an IANA + Considerations Section in RFCs", BCP + 26, RFC 2434, October 1998. + + [RFC2743] Linn, J., "Generic Security Service + Application Program Interface Version + 2, Update 1", RFC 2743, January 2000. + + [SSH-ARCH] Ylonen, T., "SSH Protocol + Architecture", I-D draft-ietf- + architecture-14.txt, July 2003. + + [SSH-TRANS] Ylonen, T., "SSH Transport Layer + Protocol", I-D draft-ietf-transport- + 16.txt, July 2003. + + [SSH-USERAUTH] Ylonen, T., "SSH Authentication + Protocol", I-D draft-ietf-userauth- + 17.txt, July 2003. + + [SSH-CONNECT] Ylonen, T., "SSH Connection Protocol", + I-D draft-ietf-connect-17.txt, July + 2003. + + [SSH-NUMBERS] Lehtinen, S. and D. Moffat, "SSH + Protocol Assigned Numbers", I-D draft- + ietf-secsh-assignednumbers-03.txt, + + + +Ylonen, et. al. Expires January 12, 2004 [Page 28] + +Internet-Draft SSH Protocol Architecture July 2003 + + + July 2003. + + [SCHNEIER] Schneier, B., "Applied Cryptography + Second Edition: protocols algorithms + and source in code in C", 1996. + + [KAUFMAN,PERLMAN,SPECINER] Kaufman, C., Perlman, R. and M. + Speciner, "Network Security: PRIVATE + Communication in a PUBLIC World", + 1995. + + [CERT] CERT Coordination Center, The., + "http://www.cert.org/nav/index_red.html" + . + + [VENEMA] Venema, W., "Murphy's Law and Computer + Security", Proceedings of 6th USENIX + Security Symposium, San Jose CA + http://www.usenix.org/publications/library/proceedings/sec96/venema.html + , July 1996. + + [ROGAWAY] Rogaway, P., "Problems with Proposed + IP Cryptography", Unpublished paper + http://www.cs.ucdavis.edu/~rogaway/papers/draft-rogaway-ipsec-comments-00.txt + , 1996. + + [DAI] Dai, W., "An attack against SSH2 + protocol", Email to the SECSH Working + Group ietf-ssh@netbsd.org + ftp://ftp.ietf.org/ietf-mail- + archive/secsh/2002-02.mail, Feb 2002. + + [BELLARE,KOHNO,NAMPREMPRE] Bellaire, M., Kohno, T. and C. + Namprempre, "Authenticated Encryption + in SSH: Fixing the SSH Binary Packet + Protocol", , Sept 2002. + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: ylo@ssh.com + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 29] + +Internet-Draft SSH Protocol Architecture July 2003 + + + Tero Kivinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: kivinen@ssh.com + + + Markku-Juhani O. Saarinen + University of Jyvaskyla + + + Timo J. Rinne + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: tri@ssh.com + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 30] + +Internet-Draft SSH Protocol Architecture July 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished + to others, and derivative works that comment on or otherwise + explain it or assist in its implementation may be prepared, + copied, published and distributed, in whole or in part, without + restriction of any kind, provided that the above copyright notice + and this paragraph are included on all such copies and derivative + works. However, this document itself may not be modified in any + way, such as by removing the copyright notice or references to the + Internet Society or other Internet organizations, except as needed + for the purpose of developing Internet standards in which case the + procedures for copyrights defined in the Internet Standards + process must be followed, or as required to translate it into + languages other than English. + + The limited permissions granted above are perpetual and will not + be revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on + an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 31] + diff --git a/doc/draft-ietf-secsh-assignednumbers-04.txt b/doc/draft-ietf-secsh-assignednumbers-04.txt new file mode 100644 index 00000000..f87ca0c7 --- /dev/null +++ b/doc/draft-ietf-secsh-assignednumbers-04.txt @@ -0,0 +1,559 @@ +Network Working Group S. Lehtinen +Internet-Draft SSH Communications Security Corp +Expires: February 13, 2004 D. Moffat + Sun Microsystems + August 15, 2003 + + + SSH Protocol Assigned Numbers + draft-ietf-secsh-assignednumbers-04.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on February 13, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + This document defines the initial state of the IANA assigned numbers + for the SSH protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH- + CONNECT], [SSH-USERAUTH]. Except for one HISTORIC algorithm + generally regarded as obsolete, this document does not define any new + protocols or any number ranges not already defined in the above + referenced documents. It is intended only for initalization of the + IANA databases referenced in those documents. + + + + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 1] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + +Table of Contents + + 1. Message Numbers . . . . . . . . . . . . . . . . . . . . . . 3 + 1.1 Disconnect Codes . . . . . . . . . . . . . . . . . . . . . . 4 + 2. Service Names . . . . . . . . . . . . . . . . . . . . . . . 5 + 2.1 Authentication Method Names . . . . . . . . . . . . . . . . 5 + 2.2 Connection Protocol Assigned Names . . . . . . . . . . . . . 6 + 2.2.1 Connection Protocol Channel Types . . . . . . . . . . . . . 6 + 2.2.2 Connection Protocol Global Request Names . . . . . . . . . . 6 + 2.2.3 Connection Protocol Channel Request Names . . . . . . . . . 6 + 3. Key Exchange Method Names . . . . . . . . . . . . . . . . . 7 + 4. Assigned Algorithm Names . . . . . . . . . . . . . . . . . . 7 + 4.1 Encryption Algorithm Names . . . . . . . . . . . . . . . . . 7 + 4.2 MAC Algorithm Names . . . . . . . . . . . . . . . . . . . . 8 + 4.3 Public Key Algorithm Names . . . . . . . . . . . . . . . . . 8 + 4.4 Compression Algorithm Names . . . . . . . . . . . . . . . . 8 + References . . . . . . . . . . . . . . . . . . . . . . . . . 8 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 9 + Full Copyright Statement . . . . . . . . . . . . . . . . . . 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 2] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + +1. Message Numbers + + The Message Number is an 8-bit value, which describes the payload of + a packet. + + Protocol packets have message numbers in the range 1 to 255. These + numbers have been allocated as follows in [SSH-ARCH]: + + Transport layer protocol: + + 1 to 19 Transport layer generic (e.g. disconnect, ignore, debug, etc.) + 20 to 29 Algorithm negotiation + 30 to 49 Key exchange method specific (numbers can be reused for + different authentication methods) + + User authentication protocol: + + 50 to 59 User authentication generic + 60 to 79 User authentication method specific (numbers can be + reused for different authentication methods) + + Connection protocol: + + 80 to 89 Connection protocol generic + 90 to 127 Channel related messages + + Reserved for client protocols: + + 128 to 191 Reserved + + Local extensions: + + 192 to 255 Local extensions + + + Requests for assignments of new message numbers must be accompanied + by an RFC which describes the new packet type. If the RFC is not on + the standards-track (i.e. it is an informational or experimental + RFC), it must be explicitly reviewed and approved by the IESG before + the RFC is published and the message number is assigned. + + Message ID Value Reference + ----------- ----- --------- + SSH_MSG_DISCONNECT 1 [SSH-TRANS] + SSH_MSG_IGNORE 2 [SSH-TRANS] + SSH_MSG_UNIMPLEMENTED 3 [SSH-TRANS] + SSH_MSG_DEBUG 4 [SSH-TRANS] + SSH_MSG_SERVICE_REQUEST 5 [SSH-TRANS] + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 3] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + + SSH_MSG_SERVICE_ACCEPT 6 [SSH-TRANS] + SSH_MSG_KEXINIT 20 [SSH-TRANS] + SSH_MSG_NEWKEYS 21 [SSH-TRANS] + SSH_MSG_KEXDH_INIT 30 [SSH-TRANS] + SSH_MSG_KEXDH_REPLY 31 [SSH-TRANS] + SSH_MSG_USERAUTH_REQUEST 50 [SSH-USERAUTH] + SSH_MSG_USERAUTH_FAILURE 51 [SSH-USERAUTH] + SSH_MSG_USERAUTH_SUCCESS 52 [SSH-USERAUTH] + SSH_MSG_USERAUTH_BANNER 53 [SSH-USERAUTH] + SSH_MSG_USERAUTH_PK_OK 60 [SSH-USERAUTH] + SSH_MSG_GLOBAL_REQUEST 80 [SSH-CONNECT] + SSH_MSG_REQUEST_SUCCESS 81 [SSH-CONNECT] + SSH_MSG_REQUEST_FAILURE 82 [SSH-CONNECT] + SSH_MSG_CHANNEL_OPEN 90 [SSH-CONNECT] + SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 [SSH-CONNECT] + SSH_MSG_CHANNEL_OPEN_FAILURE 92 [SSH-CONNECT] + SSH_MSG_CHANNEL_WINDOW_ADJUST 93 [SSH-CONNECT] + SSH_MSG_CHANNEL_DATA 94 [SSH-CONNECT] + SSH_MSG_CHANNEL_EXTENDED_DATA 95 [SSH-CONNECT] + SSH_MSG_CHANNEL_EOF 96 [SSH-CONNECT] + SSH_MSG_CHANNEL_CLOSE 97 [SSH-CONNECT] + SSH_MSG_CHANNEL_REQUEST 98 [SSH-CONNECT] + SSH_MSG_CHANNEL_SUCCESS 99 [SSH-CONNECT] + SSH_MSG_CHANNEL_FAILURE 100 [SSH-CONNECT] + + +1.1 Disconnect Codes + + The Disconnect code is an 8-bit value, which describes the disconnect + reason. Requests for assignments of new disconnect codes must be + accompanied by an RFC which describes the new disconnect reason code. + + + Disconnect code Value Reference + ---------------- ----- --------- + SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 [SSH-TRANS] + SSH_DISCONNECT_PROTOCOL_ERROR 2 [SSH-TRANS] + SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 [SSH-TRANS] + SSH_DISCONNECT_RESERVED 4 [SSH-TRANS] + SSH_DISCONNECT_MAC_ERROR 5 [SSH-TRANS] + SSH_DISCONNECT_COMPRESSION_ERROR 6 [SSH-TRANS] + SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 [SSH-TRANS] + SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 [SSH-TRANS] + SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 [SSH-TRANS] + SSH_DISCONNECT_CONNECTION_LOST 10 [SSH-TRANS] + SSH_DISCONNECT_BY_APPLICATION 11 [SSH-TRANS] + SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 [SSH-TRANS] + SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 [SSH-TRANS] + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 4] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + + SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 [SSH-TRANS] + SSH_DISCONNECT_ILLEGAL_USER_NAME 15 [SSH-TRANS] + + +2. Service Names + + The Service Name is used to describe a protocol layer. These names + MUST be printable US-ASCII strings, and MUST NOT contain the + characters at-sign ('@'), comma (','), or whitespace or control + characters (ASCII codes 32 or less). Names are case-sensitive, and + MUST NOT be longer than 64 characters. + + Requests for assignments of new service names must be accompanied by + an RFC which describes the interpretation for the service name. If + the RFC is not on the standards-track (i.e. it is an informational + or experimental RFC), it must be explicitly reviewed and approved by + the IESG before the RFC is published and the service name is + assigned. + + Service name Reference + ------------- --------- + ssh-userauth [SSH-USERAUTH] + ssh-connection [SSH-CONNECT] + + +2.1 Authentication Method Names + + The Authentication Method Name is used to describe an authentication + method for the "ssh-userauth" service [SSH-USERAUTH]. These names + MUST be printable US-ASCII strings, and MUST NOT contain the + characters at-sign ('@'), comma (','), or whitespace or control + characters (ASCII codes 32 or less). Names are case-sensitive, and + MUST NOT be longer than 64 characters. + + Requests for assignments of new authentication method names must be + accompanied by an RFC which describes the interpretation for the + authentication method. + + Method name Reference + ------------ --------- + publickey [SSH-USERAUTH, Section 4] + password [SSH-USERAUTH, Section 5] + hostbased [SSH-USERAUTH, Section 6] + none [SSH-USERAUTH, Section 2.3] + + + + + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 5] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + +2.2 Connection Protocol Assigned Names + + The following request and type names MUST be printable US-ASCII + strings, and MUST NOT contain the characters at-sign ('@'), comma + (','), or whitespace or control characters (ASCII codes 32 or less). + Names are case-sensitive, and MUST NOT be longer than 64 characters. + + Requests for assignments of new assigned names must be accompanied by + an RFC which describes the interpretation for the type or request. + +2.2.1 Connection Protocol Channel Types + + Channel type Reference + ------------ --------- + session [SSH-CONNECT, Section 4.1] + x11 [SSH-CONNECT, Section 4.3.2] + forwarded-tcpip [SSH-CONNECT, Section 5.2] + direct-tcpip [SSH-CONNECT, Section 5.2] + + +2.2.2 Connection Protocol Global Request Names + + Request type Reference + ------------ --------- + tcpip-forward [SSH-CONNECT, Section 5.1] + cancel-tcpip-forward [SSH-CONNECT, Section 5.1] + + +2.2.3 Connection Protocol Channel Request Names + + Request type Reference + ------------ --------- + pty-req [SSH-CONNECT, Section 4.2] + x11-req [SSH-CONNECT, Section 4.3.1] + env [SSH-CONNECT, Section 4.4] + shell [SSH-CONNECT, Section 4.5] + exec [SSH-CONNECT, Section 4.5] + subsystem [SSH-CONNECT, Section 4.5] + window-change [SSH-CONNECT, Section 4.7] + xon-xoff [SSH-CONNECT, Section 4.8] + signal [SSH-CONNECT, Section 4.9] + exit-status [SSH-CONNECT, Section 4.10] + exit-signal [SSH-CONNECT, Section 4.10] + + + + + + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 6] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + +3. Key Exchange Method Names + + The Key Exchange Method Name describes a key-exchange method for the + protocol [SSH-TRANS]. The names MUST be printable US-ASCII strings, + and MUST NOT contain the characters at-sign ('@'), comma (','), or + whitespace or control characters (ASCII codes 32 or less). Names are + case-sensitive, and MUST NOT be longer than 64 characters. + + Requests for assignment of new key-exchange method names must be + accompanied by a reference to a standards-track or Informational RFC + which describes this method. + + Method name Reference + ------------ --------- + diffie-hellman-group1-sha1 [SSH-TRANS, Section 4.5] + + +4. Assigned Algorithm Names + + The following identifiers (names) MUST be printable US-ASCII strings, + and MUST NOT contain the characters at-sign ('@'), comma (','), or + whitespace or control characters (ASCII codes 32 or less). Names are + case-sensitive, and MUST NOT be longer than 64 characters. + + Requests for assignment of new algorithm names must be accompanied by + a reference to a standards-track or Informational RFC or a reference + to published cryptographic literature which describes the algorithm. + +4.1 Encryption Algorithm Names + + Cipher name Reference + ------------ --------- + 3des-cbc [SSH-TRANS, Section 4.3] + blowfish-cbc [SSH-TRANS, Section 4.3] + twofish256-cbc [SSH-TRANS, Section 4.3] + twofish-cbc [SSH-TRANS, Section 4.3] + twofish192-cbc [SSH-TRANS, Section 4.3] + twofish128-cbc [SSH-TRANS, Section 4.3] + aes256-cbc [SSH-TRANS, Section 4.3] + aes192-cbc [SSH-TRANS, Section 4.3] + aes128-cbc [SSH-TRANS, Section 4.3] + serpent256-cbc [SSH-TRANS, Section 4.3] + serpent192-cbc [SSH-TRANS, Section 4.3] + serpent128-cbc [SSH-TRANS, Section 4.3] + arcfour [SSH-TRANS, Section 4.3] + idea-cbc [SSH-TRANS, Section 4.3] + cast128-cbc [SSH-TRANS, Section 4.3] + none [SSH-TRANS, Section 4.3] + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 7] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + + des-cbc [FIPS-46-3] HISTORIC; See page 4 of [FIPS 46-3] + + +4.2 MAC Algorithm Names + + + + MAC name Reference + --------- --------- + hmac-sha1 [SSH-TRANS, Section 4.4] + hmac-sha1-96 [SSH-TRANS, Section 4.4] + hmac-md5 [SSH-TRANS, Section 4.4] + hmac-md5-96 [SSH-TRANS, Section 4.4] + none [SSH-TRANS, Section 4.4] + + +4.3 Public Key Algorithm Names + + Algorithm name Reference + --------------- --------- + ssh-dss [SSH-TRANS, Section 4.6] + ssh-rsa [SSH-TRANS, Section 4.6] + x509v3-sign-rsa [SSH-TRANS, Section 4.6] + x509v3-sign-dss [SSH-TRANS, Section 4.6] + spki-sign-rsa [SSH-TRANS, Section 4.6] + spki-sign-dss [SSH-TRANS, Section 4.6] + pgp-sign-rsa [SSH-TRANS, Section 4.6] + pgp-sign-dss [SSH-TRANS, Section 4.6] + + +4.4 Compression Algorithm Names + + Algorithm name Reference + --------------- --------- + none [SSH-TRANS, Section 4.2] + zlib [SSH-TRANS, Section 4.2] + +References + + [SSH-ARCH] Ylonen, T., "SSH Protocol Architecture", I-D draft- + ietf-architecture-14.txt, July 2003. + + [SSH-TRANS] Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-16.txt, July 2003. + + [SSH-USERAUTH] Ylonen, T., "SSH Authentication Protocol", I-D draft- + ietf-userauth-17.txt, July 2003. + + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 8] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + + [SSH-CONNECT] Ylonen, T., "SSH Connection Protocol", I-D draft- + ietf-connect-17.txt, July 2003. + + [SSH-NUMBERS] Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers- + 03.txt, July 2003. + + [FIPS-46-3] U.S. Dept. of Commerce, ., "FIPS PUB 46-3, Data + Encryption Standard (DES)", October 1999. + + +Authors' Addresses + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + Darren J Moffat + Sun Microsystems + 901 San Antonio Road + Palo Alto 94303 + USA + + EMail: Darren.Moffat@Sun.COM + + + + + + + + + + + + + + + + + + + + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 9] + +Internet-Draft SSH Protocol Assigned Numbers August 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Lehtinen & Moffat Expires February 13, 2004 [Page 10] + + diff --git a/doc/draft-ietf-secsh-auth-kbdinteract-05-cleaned.txt b/doc/draft-ietf-secsh-auth-kbdinteract-05-cleaned.txt new file mode 100644 index 00000000..b22a6632 --- /dev/null +++ b/doc/draft-ietf-secsh-auth-kbdinteract-05-cleaned.txt @@ -0,0 +1,366 @@ + + Generic Message Exchange Authentication For SSH + + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. This document describes a general + purpose authentication method for the SSH protocol, suitable for + interactive authentications where the authentication data should be + entered via a keyboard. The major goal of this method is to allow + the SSH client to support a whole class of authentication + mechanism(s) without knowing the specifics of the actual + authentication mechanism(s). + +1. Introduction + + The SSH authentication protocol [SSH-USERAUTH] is a general-purpose + user authentication protocol. It is intended to be run over the SSH + transport layer protocol [SSH-TRANS]. The authentication protocol + assumes that the underlying protocols provide integrity and + confidentiality protection. + + This document describes a general purpose authentication method for + the SSH authentication protocol. This method is suitable for + interactive authentication methods which do not need any special + software support on the client side. Instead all authentication data + should be entered via the keyboard. The major goal of this method is + to allow the SSH client to have little or no knowledge of the + specifics of the underlying authentication mechanism(s) used by the + SSH server. This will allow the server to arbitrarily select or + change the underlying authentication mechanism(s) without having to + update client code. + + The name for this authentication method is "keyboard-interactive". + +2. Rationale + + Currently defined authentication methods for SSH are tightly coupled + with the underlying authentication mechanism. This makes it + difficult to add new mechanisms for authentication as all clients + must be updated to support the new mechanism. With the generic + method defined here, clients will not require code changes to support + new authentication mechanisms, and if a separate authentication layer + is used, such as [PAM], then the server may not need any code changes + either. + + This presents a significant advantage to other methods, such as the + "password" method (defined in [SSH-USERAUTH]), as new (presumably + stronger) methods may be added "at will" and system security can be + transparently enhanced. + + Challenge-response and One Time Password mechanisms are also easily + supported with this authentication method. + + This authentication method is however limited to authentication + mechanisms which do not require any special code, such as hardware + drivers or password mangling, on the client. + +3. Protocol Exchanges + + The client initiates the authentication with a + SSH_MSG_USERAUTH_REQUEST message. The server then requests + authentication information from the client with a + SSH_MSG_USERAUTH_INFO_REQUEST message. The client obtains the + information from the user and then responds with a + SSM_MSG_USERAUTH_INFO_RESPONSE message. The server MUST NOT send + another SSH_MSG_USERAUTH_INFO_REQUEST before it has received the + answer from the client. + +3.1 Initial Exchange + + The authentication starts with the client sending the following + packet: + + byte SSH_MSG_USERAUTH_REQUEST + string user name (ISO-10646 UTF-8, as defined in [RFC-2279]) + string service name (US-ASCII) + string "keyboard-interactive" (US-ASCII) + string language tag (as defined in [RFC-3066]) + string submethods (ISO-10646 UTF-8) + + The language tag is deprecated and SHOULD be the empty string. It + may be removed in a future revision of this specification. The + server SHOULD instead select the language used based on the tags + communicated during key exchange [SSH-TRANS]. + + If the language tag is not the empty string, the server SHOULD use + the specified language for any messages sent to the client as part of + this protocol. The language tag SHOULD NOT be used for language + selection for messages outside of this protocol. The language to be + used if the server does not support the requested language is + implementation-dependent. + + The submethods field is included so the user can give a hint of which + actual methods he wants to use. It is a a comma-separated list of + authentication submethods (software or hardware) which the user + prefers. If the client has knowledge of the submethods preferred by + the user, presumably through a configuration setting, it MAY use the + submethods field to pass this information to the server. Otherwise + it MUST send the empty string. + + The actual names of the submethods is something which the user and + the server needs to agree upon. + + Server interpretation of the submethods field is implementation- + dependent. + + One possible implementation strategy of the submethods field on the + server is that, unless the user may use multiple different + submethods, the server ignores this field. If the user may + authenticate using one of several different submethods the server + should treat the submethods field as a hint on which submethod the + user wants to use this time. + + Note that when this message is sent to the server, the client has not + yet prompted the user for a password, and so that information is NOT + included with this initial message (unlike the "password" method). + + The server MUST reply with either a SSH_MSG_USERAUTH_SUCCESS, + SSH_MSG_USERAUTH_FAILURE, or SSH_MSG_USERAUTH_INFO_REQUEST message. + + The server SHOULD NOT reply with the SSH_MSG_USERAUTH_FAILURE message + if the failure is based on the user name or service name; instead it + SHOULD send SSH_MSG_USERAUTH_INFO_REQUEST message(s) which look just + like the one(s) which would have been sent in cases where + authentication should proceed, and then send the failure message + (after a suitable delay, as described below). The goal is to make it + impossible to find valid usernames by just comparing the results when + authenticating as different users. + +3.2 Information Requests + + Requests are generated from the server using the + SSH_MSG_USERAUTH_INFO_REQUEST message. + + The server may send as many requests as are necessary to authenticate + the client; the client MUST be prepared to handle multiple exchanges. + However the server MUST NOT ever have more than one + SSH_MSG_USERAUTH_INFO_REQUEST message outstanding. That is, it may + not send another request before the client has answered. + + The SSH_MSG_USERAUTH_INFO_REQUEST message is defined as follows: + + byte SSH_MSG_USERAUTH_INFO_REQUEST + string name (ISO-10646 UTF-8) + string instruction (ISO-10646 UTF-8) + string language tag (as defined in [RFC-3066]) + int num-prompts + string prompt[1] (ISO-10646 UTF-8) + boolean echo[1] + ... + string prompt[num-prompts] (ISO-10646 UTF-8) + boolean echo[num-prompts] + + The server SHOULD take into consideration that some clients may not + be able to properly display a long name or prompt field (see next + section), and limit the lengths of those fields if possible. For + example, instead of an instruction field of "Enter Password" and a + prompt field of "Password for user23@host.domain: ", a better choice + might be an instruction field of + "Password authentication for user23@host.domain" and a prompt field + of "Password: ". It is expected that this authentication method + would typically be backended by [PAM] and so such choices would not + be possible. + + The name and instruction fields MAY be empty strings, the client MUST + be prepared to handle this correctly. The prompt field(s) MUST NOT + be empty strings. + + The language tag SHOULD describe the language used in the textual + fields. If the server does not know the language used, or if + multiple languages are used, the language tag MUST be the empty + string. + + The num-prompts field may be `0', in which case there will be no + prompt/echo fields in the message, but the client SHOULD still + display the name and instruction fields (as described below). + +3.3 User Interface + + Upon receiving a request message, the client SHOULD prompt the user + as follows: + + A command line interface (CLI) client SHOULD print the name and + instruction (if non-empty), adding newlines. Then for each prompt in + turn, the client SHOULD display the prompt and read the user input. + + A graphical user interface (GUI) client has many choices on how to + prompt the user. One possibility is to use the name field (possibly + + prefixed with the application's name) as the title of a dialog window + in which the prompt(s) are presented. In that dialog window, the + instruction field would be a text message, and the prompts would be + labels for text entry fields. All fields SHOULD be presented to the + user, for example an implementation SHOULD NOT discard the name field + because its windows lack titles; it SHOULD instead find another way + to display this information. If prompts are presented in a dialog + window, then the client SHOULD NOT present each prompt in a separate + window. + + All clients MUST properly handle an instruction field with embedded + newlines. They SHOULD also be able to display at least 30 characters + for the name and prompts. If the server presents names or prompts + longer than 30 characters, the client MAY truncate these fields to + the length it can display. If the client does truncate any fields, + there MUST be an obvious indication that such truncation has occured. + The instruction field SHOULD NOT be truncated. + + Clients SHOULD use control character filtering as discussed in + [SSH-ARCH] to avoid attacks by including terminal control characters + in the fields to be displayed. + + For each prompt, the corresponding echo field indicates whether or + not the user input should be echoed as characters are typed. Clients + SHOULD correctly echo/mask user input for each prompt independently + of other prompts in the request message. If a client does not honor + the echo field for whatever reason, then the client MUST err on the + side of masking input. A GUI client might like to have a checkbox + toggling echo/mask. Clients SHOULD NOT add any additional characters + to the prompt such as ": " (colon-space); the server is responsible + for supplying all text to be displayed to the user. Clients MUST + also accept empty responses from the user and pass them on as empty + strings. + +3.4 Information Responses + + After obtaining the requested information from the user, the client + MUST respond with a SSH_MSG_USERAUTH_INFO_RESPONSE message. + + The format of the SSH_MSG_USERAUTH_INFO_RESPONSE message is as + follows: + + byte SSH_MSG_USERAUTH_INFO_RESPONSE + int num-responses + string response[1] (ISO-10646 UTF-8) + ... + string response[num-responses] (ISO-10646 UTF-8) + + Note that the responses are encoded in ISO-10646 UTF-8. It is up to + the server how it interprets the responses and validates them. + However, if the client reads the responses in some other encoding + (e.g., ISO 8859-1), it MUST convert the responses to ISO-10646 UTF-8 + before transmitting. + + If the num-responses field does not match the num-prompts field in + the request message, the server MUST send a failure message. + + In the case that the server sends a `0' num-prompts field in the + request message, the client MUST send a response message with a `0' + num-responses field. + + The responses MUST be ordered as the prompts were ordered. That is, + response[n] MUST be the answer to prompt[n]. + + After receiving the response, the server MUST send either a + SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another + SSH_MSG_USERAUTH_INFO_REQUEST message. + + If the server fails to authenticate the user (through the underlying + authentication mechanism(s)), it SHOULD NOT send another request + message(s) in an attempt to obtain new authentication data, instead + it SHOULD send a failure message. The only time the server should + send multiple request messages is if additional authentication data + is needed (i.e., because there are multiple underlying authentication + mechanisms that must be used to authenticate the user). + + If the server intends to respond with a failure message, it MAY delay + for an implementation-dependent time before sending to the client. + It is suspected that implementations are likely to make the time + delay a configurable, a suggested default is 2 seconds. + +4. Authentication Examples + + Here are two example exchanges between a client and server. The + first is an example of challenge/response with a handheld token. + This is an authentication that is not otherwise possible with other + authentication methods. + + C: byte SSH_MSG_USERAUTH_REQUEST + C: string "user23" + C: string "ssh-userauth" + C: string "keyboard-interactive" + C: string "" + C: string "" + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "CRYPTOCard Authentication" + S: string "The challenge is '14315716'" + S: string "en-US" + S: int 1 + S: string "Response: " + S: boolean TRUE + + [Client prompts user for password] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 1 + C: string "6d757575" + + S: byte SSH_MSG_USERAUTH_SUCCESS + + The second example is of a standard password authentication, in + this case the user's password is expired. + + C: byte SSH_MSG_USERAUTH_REQUEST + C: string "user23" + C: string "ssh-userauth" + C: string "keyboard-interactive" + C: string "en-US" + C: string "" + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "Password Authentication" + S: string "" + S: string "en-US" + S: int 1 + S: string "Password: " + S: boolean FALSE + + [Client prompts user for password] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 1 + C: string "password" + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "Password Expired" + S: string "Your password has expired." + S: string "en-US" + S: int 2 + S: string "Enter new password: " + S: boolean FALSE + S: string "Enter it again: " + S: boolean FALSE + + [Client prompts user for new password] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 2 + C: string "newpass" + C: string "newpass" + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "Password changed" + S: string "Password successfully changed for user23." + S: string "en-US" + S: int 0 + + [Client displays message to user] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 0 + + S: byte SSH_MSG_USERAUTH_SUCCESS + +5. IANA Considerations + + The userauth type "keyboard-interactive" is used for this + authentication method. + + The following method-specific constants are used with this + authentication method: + + SSH_MSG_USERAUTH_INFO_REQUEST 60 + SSH_MSG_USERAUTH_INFO_RESPONSE 61 diff --git a/doc/draft-ietf-secsh-auth-kbdinteract-05.txt b/doc/draft-ietf-secsh-auth-kbdinteract-05.txt new file mode 100644 index 00000000..99504dbf --- /dev/null +++ b/doc/draft-ietf-secsh-auth-kbdinteract-05.txt @@ -0,0 +1,619 @@ + + + +Network Working Group F. Cusack +INTERNET-DRAFT Google, Inc. +Expires November 1, 2003 M. Forssen + Appgate AB + May 1, 2003 + + + + + Generic Message Exchange Authentication For SSH + + +Status of this Memo + + This document is an Internet-Draft and is subject to all provisions + of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + . + + The list of Internet-Draft Shadow Directories can be accessed at + . + + This Internet-Draft will expire on November 1, 2003. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. This document describes a general + purpose authentication method for the SSH protocol, suitable for + interactive authentications where the authentication data should be + entered via a keyboard. The major goal of this method is to allow + the SSH client to support a whole class of authentication + mechanism(s) without knowing the specifics of the actual + authentication mechanism(s). + + + + + + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 1] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + +1. Introduction + + The SSH authentication protocol [SSH-USERAUTH] is a general-purpose + user authentication protocol. It is intended to be run over the SSH + transport layer protocol [SSH-TRANS]. The authentication protocol + assumes that the underlying protocols provide integrity and + confidentiality protection. + + This document describes a general purpose authentication method for + the SSH authentication protocol. This method is suitable for + interactive authentication methods which do not need any special + software support on the client side. Instead all authentication data + should be entered via the keyboard. The major goal of this method is + to allow the SSH client to have little or no knowledge of the + specifics of the underlying authentication mechanism(s) used by the + SSH server. This will allow the server to arbitrarily select or + change the underlying authentication mechanism(s) without having to + update client code. + + The name for this authentication method is "keyboard-interactive". + + This document should be read only after reading the SSH architecture + document [SSH-ARCH] and the SSH authentication document + [SSH-USERAUTH]. This document freely uses terminology and notation + from both documents without reference or further explanation. + + This document also describes some of the client interaction with the + user in obtaining the authentication information. While this is + somewhat out of the scope of a protocol specification, it is + described here anyway since some aspects of the protocol are + specifically designed based on user interface issues, and omitting + this information may lead to incompatible or awkward implementations. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC-2119]. + +2. Rationale + + Currently defined authentication methods for SSH are tightly coupled + with the underlying authentication mechanism. This makes it + difficult to add new mechanisms for authentication as all clients + must be updated to support the new mechanism. With the generic + method defined here, clients will not require code changes to support + new authentication mechanisms, and if a separate authentication layer + is used, such as [PAM], then the server may not need any code changes + either. + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 2] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + This presents a significant advantage to other methods, such as the + "password" method (defined in [SSH-USERAUTH]), as new (presumably + stronger) methods may be added "at will" and system security can be + transparently enhanced. + + Challenge-response and One Time Password mechanisms are also easily + supported with this authentication method. + + This authentication method is however limited to authentication + mechanisms which do not require any special code, such as hardware + drivers or password mangling, on the client. + +3. Protocol Exchanges + + The client initiates the authentication with a + SSH_MSG_USERAUTH_REQUEST message. The server then requests + authentication information from the client with a + SSH_MSG_USERAUTH_INFO_REQUEST message. The client obtains the + information from the user and then responds with a + SSM_MSG_USERAUTH_INFO_RESPONSE message. The server MUST NOT send + another SSH_MSG_USERAUTH_INFO_REQUEST before it has received the + answer from the client. + +3.1 Initial Exchange + + The authentication starts with the client sending the following + packet: + + byte SSH_MSG_USERAUTH_REQUEST + string user name (ISO-10646 UTF-8, as defined in [RFC-2279]) + string service name (US-ASCII) + string "keyboard-interactive" (US-ASCII) + string language tag (as defined in [RFC-3066]) + string submethods (ISO-10646 UTF-8) + + The language tag is deprecated and SHOULD be the empty string. It + may be removed in a future revision of this specification. The + server SHOULD instead select the language used based on the tags + communicated during key exchange [SSH-TRANS]. + + If the language tag is not the empty string, the server SHOULD use + the specified language for any messages sent to the client as part of + this protocol. The language tag SHOULD NOT be used for language + selection for messages outside of this protocol. The language to be + used if the server does not support the requested language is + implementation-dependent. + + The submethods field is included so the user can give a hint of which + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 3] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + actual methods he wants to use. It is a a comma-separated list of + authentication submethods (software or hardware) which the user + prefers. If the client has knowledge of the submethods preferred by + the user, presumably through a configuration setting, it MAY use the + submethods field to pass this information to the server. Otherwise + it MUST send the empty string. + + The actual names of the submethods is something which the user and + the server needs to agree upon. + + Server interpretation of the submethods field is implementation- + dependent. + + One possible implementation strategy of the submethods field on the + server is that, unless the user may use multiple different + submethods, the server ignores this field. If the user may + authenticate using one of several different submethods the server + should treat the submethods field as a hint on which submethod the + user wants to use this time. + + Note that when this message is sent to the server, the client has not + yet prompted the user for a password, and so that information is NOT + included with this initial message (unlike the "password" method). + + The server MUST reply with either a SSH_MSG_USERAUTH_SUCCESS, + SSH_MSG_USERAUTH_FAILURE, or SSH_MSG_USERAUTH_INFO_REQUEST message. + + The server SHOULD NOT reply with the SSH_MSG_USERAUTH_FAILURE message + if the failure is based on the user name or service name; instead it + SHOULD send SSH_MSG_USERAUTH_INFO_REQUEST message(s) which look just + like the one(s) which would have been sent in cases where + authentication should proceed, and then send the failure message + (after a suitable delay, as described below). The goal is to make it + impossible to find valid usernames by just comparing the results when + authenticating as different users. + +3.2 Information Requests + + Requests are generated from the server using the + SSH_MSG_USERAUTH_INFO_REQUEST message. + + The server may send as many requests as are necessary to authenticate + the client; the client MUST be prepared to handle multiple exchanges. + However the server MUST NOT ever have more than one + SSH_MSG_USERAUTH_INFO_REQUEST message outstanding. That is, it may + not send another request before the client has answered. + + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 4] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + The SSH_MSG_USERAUTH_INFO_REQUEST message is defined as follows: + + byte SSH_MSG_USERAUTH_INFO_REQUEST + string name (ISO-10646 UTF-8) + string instruction (ISO-10646 UTF-8) + string language tag (as defined in [RFC-3066]) + int num-prompts + string prompt[1] (ISO-10646 UTF-8) + boolean echo[1] + ... + string prompt[num-prompts] (ISO-10646 UTF-8) + boolean echo[num-prompts] + + The server SHOULD take into consideration that some clients may not + be able to properly display a long name or prompt field (see next + section), and limit the lengths of those fields if possible. For + example, instead of an instruction field of "Enter Password" and a + prompt field of "Password for user23@host.domain: ", a better choice + might be an instruction field of + "Password authentication for user23@host.domain" and a prompt field + of "Password: ". It is expected that this authentication method + would typically be backended by [PAM] and so such choices would not + be possible. + + The name and instruction fields MAY be empty strings, the client MUST + be prepared to handle this correctly. The prompt field(s) MUST NOT + be empty strings. + + The language tag SHOULD describe the language used in the textual + fields. If the server does not know the language used, or if + multiple languages are used, the language tag MUST be the empty + string. + + The num-prompts field may be `0', in which case there will be no + prompt/echo fields in the message, but the client SHOULD still + display the name and instruction fields (as described below). + +3.3 User Interface + + Upon receiving a request message, the client SHOULD prompt the user + as follows: + + A command line interface (CLI) client SHOULD print the name and + instruction (if non-empty), adding newlines. Then for each prompt in + turn, the client SHOULD display the prompt and read the user input. + + A graphical user interface (GUI) client has many choices on how to + prompt the user. One possibility is to use the name field (possibly + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 5] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + prefixed with the application's name) as the title of a dialog window + in which the prompt(s) are presented. In that dialog window, the + instruction field would be a text message, and the prompts would be + labels for text entry fields. All fields SHOULD be presented to the + user, for example an implementation SHOULD NOT discard the name field + because its windows lack titles; it SHOULD instead find another way + to display this information. If prompts are presented in a dialog + window, then the client SHOULD NOT present each prompt in a separate + window. + + All clients MUST properly handle an instruction field with embedded + newlines. They SHOULD also be able to display at least 30 characters + for the name and prompts. If the server presents names or prompts + longer than 30 characters, the client MAY truncate these fields to + the length it can display. If the client does truncate any fields, + there MUST be an obvious indication that such truncation has occured. + The instruction field SHOULD NOT be truncated. + + Clients SHOULD use control character filtering as discussed in + [SSH-ARCH] to avoid attacks by including terminal control characters + in the fields to be displayed. + + For each prompt, the corresponding echo field indicates whether or + not the user input should be echoed as characters are typed. Clients + SHOULD correctly echo/mask user input for each prompt independently + of other prompts in the request message. If a client does not honor + the echo field for whatever reason, then the client MUST err on the + side of masking input. A GUI client might like to have a checkbox + toggling echo/mask. Clients SHOULD NOT add any additional characters + to the prompt such as ": " (colon-space); the server is responsible + for supplying all text to be displayed to the user. Clients MUST + also accept empty responses from the user and pass them on as empty + strings. + +3.4 Information Responses + + After obtaining the requested information from the user, the client + MUST respond with a SSH_MSG_USERAUTH_INFO_RESPONSE message. + + The format of the SSH_MSG_USERAUTH_INFO_RESPONSE message is as + follows: + + byte SSH_MSG_USERAUTH_INFO_RESPONSE + int num-responses + string response[1] (ISO-10646 UTF-8) + ... + string response[num-responses] (ISO-10646 UTF-8) + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 6] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + Note that the responses are encoded in ISO-10646 UTF-8. It is up to + the server how it interprets the responses and validates them. + However, if the client reads the responses in some other encoding + (e.g., ISO 8859-1), it MUST convert the responses to ISO-10646 UTF-8 + before transmitting. + + If the num-responses field does not match the num-prompts field in + the request message, the server MUST send a failure message. + + In the case that the server sends a `0' num-prompts field in the + request message, the client MUST send a response message with a `0' + num-responses field. + + The responses MUST be ordered as the prompts were ordered. That is, + response[n] MUST be the answer to prompt[n]. + + After receiving the response, the server MUST send either a + SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another + SSH_MSG_USERAUTH_INFO_REQUEST message. + + If the server fails to authenticate the user (through the underlying + authentication mechanism(s)), it SHOULD NOT send another request + message(s) in an attempt to obtain new authentication data, instead + it SHOULD send a failure message. The only time the server should + send multiple request messages is if additional authentication data + is needed (i.e., because there are multiple underlying authentication + mechanisms that must be used to authenticate the user). + + If the server intends to respond with a failure message, it MAY delay + for an implementation-dependent time before sending to the client. + It is suspected that implementations are likely to make the time + delay a configurable, a suggested default is 2 seconds. + +4. Authentication Examples + + Here are two example exchanges between a client and server. The + first is an example of challenge/response with a handheld token. + This is an authentication that is not otherwise possible with other + authentication methods. + + C: byte SSH_MSG_USERAUTH_REQUEST + C: string "user23" + C: string "ssh-userauth" + C: string "keyboard-interactive" + C: string "" + C: string "" + + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 7] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "CRYPTOCard Authentication" + S: string "The challenge is '14315716'" + S: string "en-US" + S: int 1 + S: string "Response: " + S: boolean TRUE + + [Client prompts user for password] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 1 + C: string "6d757575" + + S: byte SSH_MSG_USERAUTH_SUCCESS + + The second example is of a standard password authentication, in + this case the user's password is expired. + + C: byte SSH_MSG_USERAUTH_REQUEST + C: string "user23" + C: string "ssh-userauth" + C: string "keyboard-interactive" + C: string "en-US" + C: string "" + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "Password Authentication" + S: string "" + S: string "en-US" + S: int 1 + S: string "Password: " + S: boolean FALSE + + [Client prompts user for password] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 1 + C: string "password" + + + + + + + + + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 8] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "Password Expired" + S: string "Your password has expired." + S: string "en-US" + S: int 2 + S: string "Enter new password: " + S: boolean FALSE + S: string "Enter it again: " + S: boolean FALSE + + [Client prompts user for new password] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 2 + C: string "newpass" + C: string "newpass" + + S: byte SSH_MSG_USERAUTH_INFO_REQUEST + S: string "Password changed" + S: string "Password successfully changed for user23." + S: string "en-US" + S: int 0 + + [Client displays message to user] + + C: byte SSH_MSG_USERAUTH_INFO_RESPONSE + C: int 0 + + S: byte SSH_MSG_USERAUTH_SUCCESS + +5. IANA Considerations + + The userauth type "keyboard-interactive" is used for this + authentication method. + + The following method-specific constants are used with this + authentication method: + + SSH_MSG_USERAUTH_INFO_REQUEST 60 + SSH_MSG_USERAUTH_INFO_RESPONSE 61 + +6. Security Considerations + + The authentication protocol, and this authentication method, depends + on the security of the underlying SSH transport layer. Without the + confidentiality provided therein, any authentication data passed with + this method is subject to interception. + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 9] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + + The number of client-server exchanges required to complete an + authentication using this method may be variable. It is possible + that an observer may gain valuable information simply by counting + that number. For example, an observer may guess that a user's + password has expired, and with further observation may be able to + determine the frequency of a site's password expiration policy. + +7. References + +7.1 Normative References + + + [RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Level", BCP 14, RFC 2119, March 1997. + + + [RFC-2279] Yergeau, F., "UTF-8, a transformation format of + Unicode and ISO 10646", RFC 2279, October 1996. + + + [RFC-3066] Alvestrand, H., "Tags for the Identification of + Languages", BCP 47, RFC 3066, January 2001. + + + [SSH-ARCH] Ylonen, T., Kivinen, T, Saarinen, M., Rinne, T., and + Lehtinen, S., "SSH Protocol Architecture", work in + progress, draft-ietf-secsh-architecture-13.txt, + September, 2002. + + + [SSH-CONNECT] Ylonen, T., Kivinen, T, Saarinen, M., Rinne, T., and + Lehtinen, S., "SSH Connection Protocol", work in + progress, draft-ietf-secsh-connect-16.txt, September, + 2002. + + + [SSH-TRANS] Ylonen, T., Kivinen, T, Saarinen, M., Rinne, T., and + Lehtinen, S., "SSH Transport Layer Protocol", work in + progress, draft-ietf-secsh-transport-15.txt, + September, 2002. + + + [SSH-USERAUTH] Ylonen, T., Kivinen, T, Saarinen, M., Rinne, T., and + Lehtinen, S., "SSH Authentication Protocol", work in + progress, draft-ietf-secsh-userauth-16.txt, + September, 2002. + + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 10] + +Internet Draft SSH Generic Interactive Authentication May 1, 2003 + + +7.2 Informative References + + + [PAM] Samar, V., Schemers, R., "Unified Login With + Pluggable Authentication Modules (PAM)", OSF RFC + 86.0, October 1995 + +8. Author's Addresses + + Frank Cusack + Google, Inc. + 2400 Bayshore Parkway + Mountain View, CA 94043 + Email: frank@google.com + + Martin Forssen + Appgate AB + Stora Badhusgatan 18-20 + SE-411 21 Gothenburg + SWEDEN + Email: maf@appgate.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +F. Cusack, M. Forssen Expires November 1, 2003 [Page 11] + \ No newline at end of file diff --git a/doc/draft-ietf-secsh-break-00.txt b/doc/draft-ietf-secsh-break-00.txt new file mode 100644 index 00000000..f10763ba --- /dev/null +++ b/doc/draft-ietf-secsh-break-00.txt @@ -0,0 +1,394 @@ + + + +Secure Shell Working Group J. Galbraith +Internet-Draft VanDyke Software +Expires: September 17, 2003 P. Remaker + Cisco Systems, Inc + March 19, 2003 + + + Session Channel Break Extension + draft-ietf-secsh-break-00.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on September 17, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + The Break Extension provides a way to send a break signal during a + SSH terminal session. + + + + + + + + + + + + +Galbraith & Remaker Expires September 17, 2003 [Page 1] + +Internet-Draft Session Channel Break Extension March 2003 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. The Break Request . . . . . . . . . . . . . . . . . . . . . . . 4 + References . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 5 + Intellectual Property and Copyright Statements . . . . . . . . . 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith & Remaker Expires September 17, 2003 [Page 2] + +Internet-Draft Session Channel Break Extension March 2003 + + +1. Introduction + + The SSH session channel provides a mechanism for the client-user to + interactively enter commands and receive output from a remote host + while taking advantage of the SSH transport's privacy and integrity + features. + + A common application of the telnet protocol is the "Console Server" + whereby a telnet NVT can be connected to a physical RS-232/V.24 + asynchronous port, allowing the telnet NVT to appear as a locally + attached terminal to that port, and allowing that port to appear as a + network addressable device. A number of major computer equipment + vendors provide high level administrative functions through an + asynchronous serial port and generally expect the attached terminal + to be capable of send a BREAK signal, which is defined as the TxD + signal being held in a SPACE state for a time greater than a whole + character time, typically interpreted as 250 to 500 ms. + + The telnet protocolprovides a means to send a "BREAK" signal, which + is defined as a "a signal outside the USASCII set which is currently + given local meaning within many systems." [1] Console Server vendors + interpret the TELNET break signal as a physical break signal, which + can then allow access to the full range of administartive functions + available on an asynchronous serial console port. + + The lack of a similar facility in the SSH session channel has forced + users to continue the use of telnet for the "Console Server" + function. + + + + + + + + + + + + + + + + + + + + + + + +Galbraith & Remaker Expires September 17, 2003 [Page 3] + +Internet-Draft Session Channel Break Extension March 2003 + + +2. The Break Request + + The following following channel specific request can be sent to + request that the remote host perform a break operation. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "break" + boolean want_reply + uint32 break-length in milliseconds + + If the break length cannot be controlled by the application receiving + this request, the break length parameter SHOULD be ignored and the + default break signal length of the chipset or underlying chipset + driver SHOULD be sent. + + If the application can control the break-length, the following + suggestions are made reagarding break duration. If a break duration + request of greater than 3000ms is received, it SHOULD be processed as + a 3000ms break, in order to an unreasonably long break request + causing the port to become unavailable for as long as 47 days while + executing the break. Applications that require a longer break may + choose to ignore this requirement. If break duration request of + less than 500ms, is requested a break of 500ms SHOULD be sent since + most devices will recognize a break of that length. In the event + that an application needs a shorter break, this can be ignored. If + the break-length parameter is 0, the break SHOULD be sent as 500ms or + the default break signal length of the chipset or underlying chipset + driver . + + If the want_reply boolean is set, the server MUST reply using + SSH_MSG_CHANNEL_SUCCESS or SSH_MSG_CHANNEL_FAILURE [4] messages. If + a break of any kind was preformed, SSH_MSG_CHANNEL_SUCCESS MUST be + sent. If no break was preformed, SSH_MSG_CHANNEL_FAILURE MUST be + sent. + + This operation SHOULD be support by most general purpose SSH clients. + + + + + + + + + + + + + + +Galbraith & Remaker Expires September 17, 2003 [Page 4] + +Internet-Draft Session Channel Break Extension March 2003 + + +References + + [1] Postel, J. and J. Reynolds, "Telnet Protocol Specification", STD + 8, RFC 854, May 1983. + + [2] Rinne, T., Ylonen, T., Kivinen, T. and S. Lehtinen, "SSH + Protocol Architecture", draft-ietf-secsh-architecture-13 (work + in progress), September 2002. + + [3] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Transport Layer Protocol", + draft-ietf-secsh-transport-15 (work in progress), September + 2002. + + [4] Rinne, T., Ylonen, T., Kivinen, T. and S. Lehtinen, "SSH + Connection Protocol", draft-ietf-secsh-connect-16 (work in + progress), September 2002. + + +Authors' Addresses + + Joseph Galbraith + VanDyke Software + 4848 Tramway Ridge Blvd + Suite 101 + Albuquerque, NM 87111 + US + + Phone: +1 505 332 5700 + EMail: galb-list@vandyke.com + + + Phillip Remaker + Cisco Systems, Inc + 170 West Tasman Drive + San Jose, CA 95120 + US + + EMail: remaker@cisco.com + + + + + + + + + + + + +Galbraith & Remaker Expires September 17, 2003 [Page 5] + +Internet-Draft Session Channel Break Extension March 2003 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + + + +Galbraith & Remaker Expires September 17, 2003 [Page 6] + +Internet-Draft Session Channel Break Extension March 2003 + + + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith & Remaker Expires September 17, 2003 [Page 7] + + diff --git a/doc/draft-ietf-secsh-connect-17.txt b/doc/draft-ietf-secsh-connect-17.txt new file mode 100644 index 00000000..5a8a43e0 --- /dev/null +++ b/doc/draft-ietf-secsh-connect-17.txt @@ -0,0 +1,1232 @@ + + +Network Working Group T. Ylonen +Internet-Draft T. Kivinen +Expires: January 12, 2004 SSH Communications Security Corp + M. Saarinen + University of Jyvaskyla + T. Rinne + S. Lehtinen + SSH Communications Security Corp + July 14, 2003 + + + SSH Connection Protocol + draft-ietf-secsh-connect-17.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on January 12, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. + + This document describes the SSH Connection Protocol. It provides + interactive login sessions, remote execution of commands, + + + +Ylonen, et. al. Expires January 12, 2004 [Page 1] + +Internet-Draft SSH Connection Protocol July 2003 + + + forwarded TCP/IP connections, and forwarded X11 connections. All + of these channels are multiplexed into a single encrypted tunnel. + + The SSH Connection Protocol has been designed to run on top of the + SSH transport layer and user authentication protocols. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Global Requests . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Channel Mechanism . . . . . . . . . . . . . . . . . . . . . 3 + 3.1 Opening a Channel . . . . . . . . . . . . . . . . . . . . . 4 + 3.2 Data Transfer . . . . . . . . . . . . . . . . . . . . . . . 5 + 3.3 Closing a Channel . . . . . . . . . . . . . . . . . . . . . 6 + 3.4 Channel-Specific Requests . . . . . . . . . . . . . . . . . 7 + 4. Interactive Sessions . . . . . . . . . . . . . . . . . . . . 8 + 4.1 Opening a Session . . . . . . . . . . . . . . . . . . . . . 8 + 4.2 Requesting a Pseudo-Terminal . . . . . . . . . . . . . . . . 8 + 4.3 X11 Forwarding . . . . . . . . . . . . . . . . . . . . . . . 9 + 4.3.1 Requesting X11 Forwarding . . . . . . . . . . . . . . . . . 9 + 4.3.2 X11 Channels . . . . . . . . . . . . . . . . . . . . . . . . 9 + 4.4 Environment Variable Passing . . . . . . . . . . . . . . . . 10 + 4.5 Starting a Shell or a Command . . . . . . . . . . . . . . . 10 + 4.6 Session Data Transfer . . . . . . . . . . . . . . . . . . . 11 + 4.7 Window Dimension Change Message . . . . . . . . . . . . . . 11 + 4.8 Local Flow Control . . . . . . . . . . . . . . . . . . . . . 12 + 4.9 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 4.10 Returning Exit Status . . . . . . . . . . . . . . . . . . . 12 + 5. TCP/IP Port Forwarding . . . . . . . . . . . . . . . . . . . 14 + 5.1 Requesting Port Forwarding . . . . . . . . . . . . . . . . . 14 + 5.2 TCP/IP Forwarding Channels . . . . . . . . . . . . . . . . . 15 + 6. Encoding of Terminal Modes . . . . . . . . . . . . . . . . . 16 + 7. Summary of Message Numbers . . . . . . . . . . . . . . . . . 18 + 8. Security Considerations . . . . . . . . . . . . . . . . . . 18 + 9. Intellectual Property . . . . . . . . . . . . . . . . . . . 18 + 10. Additional Information . . . . . . . . . . . . . . . . . . . 19 + References . . . . . . . . . . . . . . . . . . . . . . . . . 19 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 20 + Full Copyright Statement . . . . . . . . . . . . . . . . . . 22 + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 2] + +Internet-Draft SSH Connection Protocol July 2003 + + + 1. Introduction + + The SSH Connection Protocol has been designed to run on top of the + SSH transport layer and user authentication protocols. It + provides interactive login sessions, remote execution of commands, + forwarded TCP/IP connections, and forwarded X11 connections. The + service name for this protocol (after user authentication) is + "ssh-connection". + + This document should be read only after reading the SSH + architecture document [SSH-ARCH]. This document freely uses + terminology and notation from the architecture document without + reference or further explanation. + + 2. Global Requests + + There are several kinds of requests that affect the state of the + remote end "globally", independent of any channels. An example is + a request to start TCP/IP forwarding for a specific port. All + such requests use the following format. + + byte SSH_MSG_GLOBAL_REQUEST + string request name (restricted to US-ASCII) + boolean want reply + ... request-specific data follows + + Request names follow the DNS extensibility naming convention + outlined in [SSH-ARCH]. + + The recipient will respond to this message with + SSH_MSG_REQUEST_SUCCESS or SSH_MSG_REQUEST_FAILURE if `want reply' + is TRUE. + + byte SSH_MSG_REQUEST_SUCCESS + ..... response specific data + + Usually the response specific data is non-existent. + + If the recipient does not recognize or support the request, it + simply responds with SSH_MSG_REQUEST_FAILURE. + + byte SSH_MSG_REQUEST_FAILURE + + + 3. Channel Mechanism + + All terminal sessions, forwarded connections, etc. are channels. + Either side may open a channel. Multiple channels are multiplexed + + + +Ylonen, et. al. Expires January 12, 2004 [Page 3] + +Internet-Draft SSH Connection Protocol July 2003 + + + into a single connection. + + Channels are identified by numbers at each end. The number + referring to a channel may be different on each side. Requests to + open a channel contain the sender's channel number. Any other + channel-related messages contain the recipient's channel number + for the channel. + + Channels are flow-controlled. No data may be sent to a channel + until a message is received to indicate that window space is + available. + + 3.1 Opening a Channel + + When either side wishes to open a new channel, it allocates a + local number for the channel. It then sends the following message + to the other side, and includes the local channel number and + initial window size in the message. + + byte SSH_MSG_CHANNEL_OPEN + string channel type (restricted to US-ASCII) + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + ... channel type specific data follows + + The channel type is a name as described in the SSH architecture + document, with similar extension mechanisms. `sender channel' is + a local identifier for the channel used by the sender of this + message. `initial window size' specifies how many bytes of + channel data can be sent to the sender of this message without + adjusting the window. `Maximum packet size' specifies the maximum + size of an individual data packet that can be sent to the sender + (for example, one might want to use smaller packets for + interactive connections to get better interactive response on slow + links). + + The remote side then decides whether it can open the channel, and + responds with either + + byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION + uint32 recipient channel + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + ... channel type specific data follows + + where `recipient channel' is the channel number given in the + + + +Ylonen, et. al. Expires January 12, 2004 [Page 4] + +Internet-Draft SSH Connection Protocol July 2003 + + + original open request, and `sender channel' is the channel number + allocated by the other side, or + + byte SSH_MSG_CHANNEL_OPEN_FAILURE + uint32 recipient channel + uint32 reason code + string additional textual information (ISO-10646 UTF-8 [RFC2279]) + string language tag (as defined in [RFC1766]) + + If the recipient of the SSH_MSG_CHANNEL_OPEN message does not + support the specified channel type, it simply responds with + SSH_MSG_CHANNEL_OPEN_FAILURE. The client MAY show the additional + information to the user. If this is done, the client software + should take the precautions discussed in [SSH-ARCH]. + + The following reason codes are defined: + + #define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 + #define SSH_OPEN_CONNECT_FAILED 2 + #define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3 + #define SSH_OPEN_RESOURCE_SHORTAGE 4 + + + 3.2 Data Transfer + + The window size specifies how many bytes the other party can send + before it must wait for the window to be adjusted. Both parties + use the following message to adjust the window. + + byte SSH_MSG_CHANNEL_WINDOW_ADJUST + uint32 recipient channel + uint32 bytes to add + + After receiving this message, the recipient MAY send the given + number of bytes more than it was previously allowed to send; the + window size is incremented. + + Data transfer is done with messages of the following type. + + byte SSH_MSG_CHANNEL_DATA + uint32 recipient channel + string data + + The maximum amount of data allowed is the current window size. + The window size is decremented by the amount of data sent. Both + parties MAY ignore all extra data sent after the allowed window is + empty. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 5] + +Internet-Draft SSH Connection Protocol July 2003 + + + Additionally, some channels can transfer several types of data. + An example of this is stderr data from interactive sessions. Such + data can be passed with SSH_MSG_CHANNEL_EXTENDED_DATA messages, + where a separate integer specifies the type of the data. The + available types and their interpretation depend on the type of the + channel. + + byte SSH_MSG_CHANNEL_EXTENDED_DATA + uint32 recipient_channel + uint32 data_type_code + string data + + Data sent with these messages consumes the same window as ordinary + data. + + Currently, only the following type is defined. + + #define SSH_EXTENDED_DATA_STDERR 1 + + + 3.3 Closing a Channel + + When a party will no longer send more data to a channel, it SHOULD + send SSH_MSG_CHANNEL_EOF. + + byte SSH_MSG_CHANNEL_EOF + uint32 recipient_channel + + No explicit response is sent to this message; however, the + application may send EOF to whatever is at the other end of the + channel. Note that the channel remains open after this message, + and more data may still be sent in the other direction. This + message does not consume window space and can be sent even if no + window space is available. + + When either party wishes to terminate the channel, it sends + SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST + send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this + message for the channel. The channel is considered closed for a + party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, + and the party may then reuse the channel number. A party MAY send + SSH_MSG_CHANNEL_CLOSE without having sent or received + SSH_MSG_CHANNEL_EOF. + + byte SSH_MSG_CHANNEL_CLOSE + uint32 recipient_channel + + This message does not consume window space and can be sent even if + + + +Ylonen, et. al. Expires January 12, 2004 [Page 6] + +Internet-Draft SSH Connection Protocol July 2003 + + + no window space is available. + + It is recommended that any data sent before this message is + delivered to the actual destination, if possible. + + 3.4 Channel-Specific Requests + + Many channel types have extensions that are specific to that + particular channel type. An example is requesting a pty (pseudo + terminal) for an interactive session. + + All channel-specific requests use the following format. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string request type (restricted to US-ASCII) + boolean want reply + ... type-specific data + + If want reply is FALSE, no response will be sent to the request. + Otherwise, the recipient responds with either + SSH_MSG_CHANNEL_SUCCESS or SSH_MSG_CHANNEL_FAILURE, or request- + specific continuation messages. If the request is not recognized + or is not supported for the channel, SSH_MSG_CHANNEL_FAILURE is + returned. + + This message does not consume window space and can be sent even if + no window space is available. Request types are local to each + channel type. + + The client is allowed to send further messages without waiting for + the response to the request. + + request type names follow the DNS extensibility naming convention + outlined in [SSH-ARCH] + + byte SSH_MSG_CHANNEL_SUCCESS + uint32 recipient_channel + + + byte SSH_MSG_CHANNEL_FAILURE + uint32 recipient_channel + + These messages do not consume window space and can be sent even if + no window space is available. + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 7] + +Internet-Draft SSH Connection Protocol July 2003 + + + 4. Interactive Sessions + + A session is a remote execution of a program. The program may be + a shell, an application, a system command, or some built-in + subsystem. It may or may not have a tty, and may or may not + involve X11 forwarding. Multiple sessions can be active + simultaneously. + + 4.1 Opening a Session + + A session is started by sending the following message. + + byte SSH_MSG_CHANNEL_OPEN + string "session" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + + Client implementations SHOULD reject any session channel open + requests to make it more difficult for a corrupt server to attack + the client. + + 4.2 Requesting a Pseudo-Terminal + + A pseudo-terminal can be allocated for the session by sending the + following message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient_channel + string "pty-req" + boolean want_reply + string TERM environment variable value (e.g., vt100) + uint32 terminal width, characters (e.g., 80) + uint32 terminal height, rows (e.g., 24) + uint32 terminal width, pixels (e.g., 640) + uint32 terminal height, pixels (e.g., 480) + string encoded terminal modes + + The encoding of terminal modes is described in Section Encoding of + Terminal Modes (Section 6). Zero dimension parameters MUST be + ignored. The character/row dimensions override the pixel + dimensions (when nonzero). Pixel dimensions refer to the drawable + area of the window. + + The dimension parameters are only informational. + + The client SHOULD ignore pty requests. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 8] + +Internet-Draft SSH Connection Protocol July 2003 + + + 4.3 X11 Forwarding + + 4.3.1 Requesting X11 Forwarding + + X11 forwarding may be requested for a session by sending + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "x11-req" + boolean want reply + boolean single connection + string x11 authentication protocol + string x11 authentication cookie + uint32 x11 screen number + + It is recommended that the authentication cookie that is sent be a + fake, random cookie, and that the cookie is checked and replaced + by the real cookie when a connection request is received. + + X11 connection forwarding should stop when the session channel is + closed; however, already opened forwardings should not be + automatically closed when the session channel is closed. + + If `single connection' is TRUE, only a single connection should be + forwarded. No more connections will be forwarded after the first, + or after the session channel has been closed. + + The `x11 authentication protocol' is the name of the X11 + authentication method used, e.g. "MIT-MAGIC-COOKIE-1". + + The x11 authentication cookie MUST be hexadecimal encoded. + + X Protocol is documented in [SCHEIFLER]. + + 4.3.2 X11 Channels + + X11 channels are opened with a channel open request. The + resulting channels are independent of the session, and closing the + session channel does not close the forwarded X11 channels. + + byte SSH_MSG_CHANNEL_OPEN + string "x11" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + string originator address (e.g. "192.168.7.38") + uint32 originator port + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 9] + +Internet-Draft SSH Connection Protocol July 2003 + + + The recipient should respond with + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or SSH_MSG_CHANNEL_OPEN_FAILURE. + + Implementations MUST reject any X11 channel open requests if they + have not requested X11 forwarding. + + 4.4 Environment Variable Passing + + Environment variables may be passed to the shell/command to be + started later. Uncontrolled setting of environment variables in a + privileged process can be a security hazard. It is recommended + that implementations either maintain a list of allowable variable + names or only set environment variables after the server process + has dropped sufficient privileges. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "env" + boolean want reply + string variable name + string variable value + + + 4.5 Starting a Shell or a Command + + Once the session has been set up, a program is started at the + remote end. The program can be a shell, an application program or + a subsystem with a host-independent name. Only one of these + requests can succeed per channel. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "shell" + boolean want reply + + This message will request the user's default shell (typically + defined in /etc/passwd in UNIX systems) to be started at the other + end. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "exec" + boolean want reply + string command + + This message will request the server to start the execution of the + given command. The command string may contain a path. Normal + precautions MUST be taken to prevent the execution of unauthorized + + + +Ylonen, et. al. Expires January 12, 2004 [Page 10] + +Internet-Draft SSH Connection Protocol July 2003 + + + commands. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "subsystem" + boolean want reply + string subsystem name + + This last form executes a predefined subsystem. It is expected + that these will include a general file transfer mechanism, and + possibly other features. Implementations may also allow + configuring more such mechanisms. As the user's shell is usually + used to execute the subsystem, it is advisable for the subsystem + protocol to have a "magic cookie" at the beginning of the protocol + transaction to distinguish it from arbitrary output generated by + shell initialization scripts etc. This spurious output from the + shell may be filtered out either at the server or at the client. + + The server SHOULD not halt the execution of the protocol stack + when starting a shell or a program. All input and output from + these SHOULD be redirected to the channel or to the encrypted + tunnel. + + It is RECOMMENDED to request and check the reply for these + messages. The client SHOULD ignore these messages. + + Subsystem names follow the DNS extensibility naming convention + outlined in [SSH-ARCH]. + + 4.6 Session Data Transfer + + Data transfer for a session is done using SSH_MSG_CHANNEL_DATA and + SSH_MSG_CHANNEL_EXTENDED_DATA packets and the window mechanism. + The extended data type SSH_EXTENDED_DATA_STDERR has been defined + for stderr data. + + 4.7 Window Dimension Change Message + + When the window (terminal) size changes on the client side, it MAY + send a message to the other side to inform it of the new + dimensions. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient_channel + string "window-change" + boolean FALSE + uint32 terminal width, columns + uint32 terminal height, rows + + + +Ylonen, et. al. Expires January 12, 2004 [Page 11] + +Internet-Draft SSH Connection Protocol July 2003 + + + uint32 terminal width, pixels + uint32 terminal height, pixels + + No response SHOULD be sent to this message. + + 4.8 Local Flow Control + + On many systems, it is possible to determine if a pseudo-terminal + is using control-S/control-Q flow control. When flow control is + allowed, it is often desirable to do the flow control at the + client end to speed up responses to user requests. This is + facilitated by the following notification. Initially, the server + is responsible for flow control. (Here, again, client means the + side originating the session, and server means the other side.) + + The message below is used by the server to inform the client when + it can or cannot perform flow control (control-S/control-Q + processing). If `client can do' is TRUE, the client is allowed to + do flow control using control-S and control-Q. The client MAY + ignore this message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "xon-xoff" + boolean FALSE + boolean client can do + + No response is sent to this message. + + 4.9 Signals + + A signal can be delivered to the remote process/service using the + following message. Some systems may not implement signals, in + which case they SHOULD ignore this message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "signal" + boolean FALSE + string signal name without the "SIG" prefix. + + Signal names will be encoded as discussed in the "exit-signal" + SSH_MSG_CHANNEL_REQUEST. + + 4.10 Returning Exit Status + + When the command running at the other end terminates, the + following message can be sent to return the exit status of the + + + +Ylonen, et. al. Expires January 12, 2004 [Page 12] + +Internet-Draft SSH Connection Protocol July 2003 + + + command. Returning the status is RECOMMENDED. No acknowledgment + is sent for this message. The channel needs to be closed with + SSH_MSG_CHANNEL_CLOSE after this message. + + The client MAY ignore these messages. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient_channel + string "exit-status" + boolean FALSE + uint32 exit_status + + The remote command may also terminate violently due to a signal. + Such a condition can be indicated by the following message. A + zero exit_status usually means that the command terminated + successfully. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "exit-signal" + boolean FALSE + string signal name without the "SIG" prefix. + boolean core dumped + string error message (ISO-10646 UTF-8) + string language tag (as defined in [RFC1766]) + + The signal name is one of the following (these are from [POSIX]) + + ABRT + ALRM + FPE + HUP + ILL + INT + KILL + PIPE + QUIT + SEGV + TERM + USR1 + USR2 + + Additional signal names MAY be sent in the format "sig-name@xyz", + where `sig-name' and `xyz' may be anything a particular + implementor wants (except the `@' sign). However, it is suggested + that if a `configure' script is used, the non-standard signal + names it finds be encoded as "SIG@xyz.config.guess", where `SIG' + is the signal name without the "SIG" prefix, and `xyz' be the host + + + +Ylonen, et. al. Expires January 12, 2004 [Page 13] + +Internet-Draft SSH Connection Protocol July 2003 + + + type, as determined by `config.guess'. + + The `error message' contains an additional explanation of the + error message. The message may consist of multiple lines. The + client software MAY display this message to the user. If this is + done, the client software should take the precautions discussed in + [SSH-ARCH]. + + 5. TCP/IP Port Forwarding + + 5.1 Requesting Port Forwarding + + A party need not explicitly request forwardings from its own end + to the other direction. However, if it wishes that connections to + a port on the other side be forwarded to the local side, it must + explicitly request this. + + + byte SSH_MSG_GLOBAL_REQUEST + string "tcpip-forward" + boolean want reply + string address to bind (e.g. "0.0.0.0") + uint32 port number to bind + + `Address to bind' and `port number to bind' specify the IP address + and port to which the socket to be listened is bound. The address + should be "0.0.0.0" if connections are allowed from anywhere. + (Note that the client can still filter connections based on + information passed in the open request.) + + Implementations should only allow forwarding privileged ports if + the user has been authenticated as a privileged user. + + Client implementations SHOULD reject these messages; they are + normally only sent by the client. + + + If a client passes 0 as port number to bind and has want reply + TRUE then the server allocates the next available unprivileged + port number and replies with the following message, otherwise + there is no response specific data. + + + byte SSH_MSG_GLOBAL_REQUEST_SUCCESS + uint32 port that was bound on the server + + A port forwarding can be cancelled with the following message. + Note that channel open requests may be received until a reply to + + + +Ylonen, et. al. Expires January 12, 2004 [Page 14] + +Internet-Draft SSH Connection Protocol July 2003 + + + this message is received. + + byte SSH_MSG_GLOBAL_REQUEST + string "cancel-tcpip-forward" + boolean want reply + string address_to_bind (e.g. "127.0.0.1") + uint32 port number to bind + + Client implementations SHOULD reject these messages; they are + normally only sent by the client. + + 5.2 TCP/IP Forwarding Channels + + When a connection comes to a port for which remote forwarding has + been requested, a channel is opened to forward the port to the + other side. + + byte SSH_MSG_CHANNEL_OPEN + string "forwarded-tcpip" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + string address that was connected + uint32 port that was connected + string originator IP address + uint32 originator port + + Implementations MUST reject these messages unless they have + previously requested a remote TCP/IP port forwarding with the + given port number. + + When a connection comes to a locally forwarded TCP/IP port, the + following packet is sent to the other side. Note that these + messages MAY be sent also for ports for which no forwarding has + been explicitly requested. The receiving side must decide whether + to allow the forwarding. + + byte SSH_MSG_CHANNEL_OPEN + string "direct-tcpip" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + string host to connect + uint32 port to connect + string originator IP address + uint32 originator port + + `Host to connect' and `port to connect' specify the TCP/IP host + + + +Ylonen, et. al. Expires January 12, 2004 [Page 15] + +Internet-Draft SSH Connection Protocol July 2003 + + + and port where the recipient should connect the channel. `Host to + connect' may be either a domain name or a numeric IP address. + + `Originator IP address' is the numeric IP address of the machine + where the connection request comes from, and `originator port' is + the port on the originator host from where the connection came + from. + + Forwarded TCP/IP channels are independent of any sessions, and + closing a session channel does not in any way imply that forwarded + connections should be closed. + + Client implementations SHOULD reject direct TCP/IP open requests + for security reasons. + + 6. Encoding of Terminal Modes + + Terminal modes (as passed in a pty request) are encoded into a + byte stream. It is intended that the coding be portable across + different environments. + + The tty mode description is a stream of bytes. The stream + consists of opcode-argument pairs. It is terminated by opcode + TTY_OP_END (0). Opcodes 1 to 159 have a single uint32 argument. + Opcodes 160 to 255 are not yet defined, and cause parsing to stop + (they should only be used after any other data). + + The client SHOULD put in the stream any modes it knows about, and + the server MAY ignore any modes it does not know about. This + allows some degree of machine-independence, at least between + systems that use a POSIX-like tty interface. The protocol can + support other systems as well, but the client may need to fill + reasonable values for a number of parameters so the server pty + gets set to a reasonable mode (the server leaves all unspecified + mode bits in their default values, and only some combinations make + sense). + + The following opcodes have been defined. The naming of opcodes + mostly follows the POSIX terminal mode flags. + + 0 TTY_OP_END Indicates end of options. + 1 VINTR Interrupt character; 255 if none. Similarly for the + other characters. Not all of these characters are + supported on all systems. + 2 VQUIT The quit character (sends SIGQUIT signal on POSIX + systems). + 3 VERASE Erase the character to left of the cursor. + 4 VKILL Kill the current input line. + + + +Ylonen, et. al. Expires January 12, 2004 [Page 16] + +Internet-Draft SSH Connection Protocol July 2003 + + + 5 VEOF End-of-file character (sends EOF from the terminal). + 6 VEOL End-of-line character in addition to carriage return + and/or linefeed. + 7 VEOL2 Additional end-of-line character. + 8 VSTART Continues paused output (normally control-Q). + 9 VSTOP Pauses output (normally control-S). + 10 VSUSP Suspends the current program. + 11 VDSUSP Another suspend character. + 12 VREPRINT Reprints the current input line. + 13 VWERASE Erases a word left of cursor. + 14 VLNEXT Enter the next character typed literally, even if it + is a special character + 15 VFLUSH Character to flush output. + 16 VSWTCH Switch to a different shell layer. + 17 VSTATUS Prints system status line (load, command, pid etc). + 18 VDISCARD Toggles the flushing of terminal output. + 30 IGNPAR The ignore parity flag. The parameter SHOULD be 0 if + this flag is FALSE set, and 1 if it is TRUE. + 31 PARMRK Mark parity and framing errors. + 32 INPCK Enable checking of parity errors. + 33 ISTRIP Strip 8th bit off characters. + 34 INLCR Map NL into CR on input. + 35 IGNCR Ignore CR on input. + 36 ICRNL Map CR to NL on input. + 37 IUCLC Translate uppercase characters to lowercase. + 38 IXON Enable output flow control. + 39 IXANY Any char will restart after stop. + 40 IXOFF Enable input flow control. + 41 IMAXBEL Ring bell on input queue full. + 50 ISIG Enable signals INTR, QUIT, [D]SUSP. + 51 ICANON Canonicalize input lines. + 52 XCASE Enable input and output of uppercase characters by + preceding their lowercase equivalents with `\'. + 53 ECHO Enable echoing. + 54 ECHOE Visually erase chars. + 55 ECHOK Kill character discards current line. + 56 ECHONL Echo NL even if ECHO is off. + 57 NOFLSH Don't flush after interrupt. + 58 TOSTOP Stop background jobs from output. + 59 IEXTEN Enable extensions. + 60 ECHOCTL Echo control characters as ^(Char). + 61 ECHOKE Visual erase for line kill. + 62 PENDIN Retype pending input. + 70 OPOST Enable output processing. + 71 OLCUC Convert lowercase to uppercase. + 72 ONLCR Map NL to CR-NL. + 73 OCRNL Translate carriage return to newline (output). + 74 ONOCR Translate newline to carriage return-newline + + + +Ylonen, et. al. Expires January 12, 2004 [Page 17] + +Internet-Draft SSH Connection Protocol July 2003 + + + (output). + 75 ONLRET Newline performs a carriage return (output). + 90 CS7 7 bit mode. + 91 CS8 8 bit mode. + 92 PARENB Parity enable. + 93 PARODD Odd parity, else even. + + 128 TTY_OP_ISPEED Specifies the input baud rate in bits per second. + 129 TTY_OP_OSPEED Specifies the output baud rate in bits per second. + + + 7. Summary of Message Numbers + + #define SSH_MSG_GLOBAL_REQUEST 80 + #define SSH_MSG_REQUEST_SUCCESS 81 + #define SSH_MSG_REQUEST_FAILURE 82 + #define SSH_MSG_CHANNEL_OPEN 90 + #define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 + #define SSH_MSG_CHANNEL_OPEN_FAILURE 92 + #define SSH_MSG_CHANNEL_WINDOW_ADJUST 93 + #define SSH_MSG_CHANNEL_DATA 94 + #define SSH_MSG_CHANNEL_EXTENDED_DATA 95 + #define SSH_MSG_CHANNEL_EOF 96 + #define SSH_MSG_CHANNEL_CLOSE 97 + #define SSH_MSG_CHANNEL_REQUEST 98 + #define SSH_MSG_CHANNEL_SUCCESS 99 + #define SSH_MSG_CHANNEL_FAILURE 100 + + + 8. Security Considerations + + This protocol is assumed to run on top of a secure, authenticated + transport. User authentication and protection against network- + level attacks are assumed to be provided by the underlying + protocols. + + It is RECOMMENDED that implementations disable all the potentially + dangerous features (e.g. agent forwarding, X11 forwarding, and + TCP/IP forwarding) if the host key has changed. + + Full security considerations for this protocol are provided in + Section 8 of [SSH-ARCH] + + 9. Intellectual Property + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described + + + +Ylonen, et. al. Expires January 12, 2004 [Page 18] + +Internet-Draft SSH Connection Protocol July 2003 + + + in this document or the extent to which any license under such + rights might or might not be available; neither does it represent + that it has made any effort to identify any such rights. + Information on the IETF's procedures with respect to rights in + standards-track and standards-related documentation can be found + in BCP-11. Copies of claims of rights made available for + publication and any assurances of licenses to be made available, + or the result of an attempt made to obtain a general license or + permission for the use of such proprietary rights by implementers + or users of this specification can be obtained from the IETF + Secretariat. + + The IETF has been notified of intellectual property rights claimed + in regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + 10. Additional Information + + The current document editor is: Darren.Moffat@Sun.COM. Comments + on this internet draft should be sent to the IETF SECSH working + group, details at: http://ietf.org/html.charters/secsh- + charter.html + +References + + [RFC1766] Alvestrand, H., "Tags for the Identification of + Languages", RFC 1766, March 1995. + + [RFC1884] Hinden, R., Deering, S. and Editors, "IP Version 6 + Addressing Architecture", RFC 1884, December 1995. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of + ISO 10646", RFC 2279, January 1998. + + [SCHEIFLER] Scheifler, R., "X Window System : The Complete + Reference to Xlib, X Protocol, Icccm, Xlfd, 3rd + edition.", Digital Press ISBN 1555580882, Feburary + 1992. + + [POSIX] ISO/IEC, 9945-1., "Information technology -- + Portable Operating System Interface (POSIX)-Part + 1: System Application Program Interface (API) C + Language", ANSI/IEE Std 1003.1, July 1996. + + [SSH-ARCH] Ylonen, T., "SSH Protocol Architecture", I-D + draft-ietf-architecture-14.txt, July 2003. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 19] + +Internet-Draft SSH Connection Protocol July 2003 + + + [SSH-TRANS] Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-16.txt, July 2003. + + [SSH-USERAUTH] Ylonen, T., "SSH Authentication Protocol", I-D + draft-ietf-userauth-17.txt, July 2003. + + [SSH-CONNECT] Ylonen, T., "SSH Connection Protocol", I-D draft- + ietf-connect-17.txt, July 2003. + + [SSH-NUMBERS] Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers- + 03.txt, July 2003. + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: ylo@ssh.com + + + Tero Kivinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: kivinen@ssh.com + + + Markku-Juhani O. Saarinen + University of Jyvaskyla + + + Timo J. Rinne + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: tri@ssh.com + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 20] + +Internet-Draft SSH Connection Protocol July 2003 + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 21] + +Internet-Draft SSH Connection Protocol July 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished + to others, and derivative works that comment on or otherwise + explain it or assist in its implementation may be prepared, + copied, published and distributed, in whole or in part, without + restriction of any kind, provided that the above copyright notice + and this paragraph are included on all such copies and derivative + works. However, this document itself may not be modified in any + way, such as by removing the copyright notice or references to the + Internet Society or other Internet organizations, except as needed + for the purpose of developing Internet standards in which case the + procedures for copyrights defined in the Internet Standards + process must be followed, or as required to translate it into + languages other than English. + + The limited permissions granted above are perpetual and will not + be revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on + an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 22] + diff --git a/doc/draft-ietf-secsh-dh-group-exchange-04.txt b/doc/draft-ietf-secsh-dh-group-exchange-04.txt new file mode 100644 index 00000000..ee6b2fb8 --- /dev/null +++ b/doc/draft-ietf-secsh-dh-group-exchange-04.txt @@ -0,0 +1,451 @@ + + + + + + +Network Working Group Markus Friedl +INTERNET-DRAFT Niels Provos +Expires in six months William A. Simpson + July 2003 + + + Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol + draft-ietf-secsh-dh-group-exchange-04.txt + + +1. Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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 docu- + ments at any time. It is inappropriate to use Internet- Drafts as + reference material or to cite them other than as "work in + progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + +2. Copyright Notice + + Copyright (C) 2000-2003 by Markus Friedl, Niels Provos and William + A. Simpson. + +3. Abstract + + This memo describes a new key exchange method for the SSH protocol. + It allows the SSH server to propose to the client new groups on + which to perform the Diffie-Hellman key exchange. The proposed + groups need not be fixed and can change with time. + +4. Overview and Rational + + SSH [4,5,6,7] is a a very common protocol for secure remote login + on the Internet. Currently, SSH performs the initial key exchange + + + +Friedl/Provos/Simpson expires in six months [Page 1] + +INTERNET DRAFT July 2003 + + + using the "diffie-hellman-group1-sha1" method. This method pre- + scribes a fixed group on which all operations are performed. + + The Diffie-Hellman key exchange provides a shared secret that can + not be determined by either party alone. In SSH, the key exchange + is signed with the host key to provide host authentication. + + The security of the Diffie-Hellman key exchange is based on the + difficulty of solving the Discrete Logarithm Problem (DLP). Since + we expect that the SSH protocol will be in use for many years in + the future, we fear that extensive precomputation and more effi- + cient algorithms to compute the discrete logarithm over a fixed + group might pose a security threat to the SSH protocol. + + The ability to propose new groups will reduce the incentive to use + precomputation for more efficient calculation of the discrete loga- + rithm. The server can constantly compute new groups in the back- + ground. + +5. Diffie-Hellman Group and Key Exchange + + The server keeps a list of safe primes and corresponding generators + that it can select from. A prime p is safe, if p = 2q + 1, and q + is prime. New primes can be generated in the background. + + The generator g should be chosen such that the order of the gener- + ated subgroup does not factor into small primes, i.e., with p = 2q + + 1, the order has to be either q or p - 1. If the order is p - 1, + then the exponents generate all possible public-values, evenly dis- + tributed throughout the range of the modulus p, without cycling + through a smaller subset. Such a generator is called a "primitive + root" (which is trivial to find when p is "safe"). + + Implementation Notes: + + One useful technique is to select the generator, and then + limit the modulus selection sieve to primes with that genera- + tor: + + 2 when p (mod 24) = 11. + 5 when p (mod 10) = 3 or 7. + + It is recommended to use 2 as generator, because it improves + efficiency in multiplication performance. It is usable even + when it is not a primitive root, as it still covers half of + the space of possible residues. + + + + + +Friedl/Provos/Simpson expires in six months [Page 2] + +INTERNET DRAFT July 2003 + + + The client requests a modulus from the server indicating the pre- + ferred size. In the following description (C is the client, S is + the server; the modulus p is a large safe prime and g is a genera- + tor for a subgroup of GF(p); min is the minimal size of p in bits + that is acceptable to the client; n is the size of the modulus p in + bits that the client would like to receive from the server; max is + the maximal size of p in bits that the client can accept; V_S is + S's version string; V_C is C's version string; K_S is S's public + host key; I_C is C's KEXINIT message and I_S S's KEXINIT message + which have been exchanged before this part begins): + + 1. C sends "min || n || max" to S, indicating the minimal accept- + able group size, the preferred size of the group and the maxi- + mal group size in bits the client will accept. + + 2. S finds a group that best matches the client's request, and + sends "p || g" to C. + + 3. C generates a random number x (1 < x < (p-1)/2). It computes e + = g^x mod p, and sends "e" to S. + + 4. S generates a random number y (0 < y < (p-1)/2) and computes f + = g^y mod p. S receives "e". It computes K = e^y mod p, H = + hash(V_C || V_S || I_C || I_S || K_S || min || n || max || p + || g || e || f || K) (these elements are encoded according to + their types; see below), and signature s on H with its private + host key. S sends "K_S || f || s" to C. The signing opera- + tion may involve a second hashing operation. + + Implementation Notes: + + To increase the speed of the key exchange, both client + and server may reduce the size of their private expo- + nents. It should be at least twice as long as the key + material that is generated from the shared secret. For + more details see the paper by van Oorschot and Wiener + [1]. + + 5. C verifies that K_S really is the host key for S (e.g. using + certificates or a local database). C is also allowed to + accept the key without verification; however, doing so will + render the protocol insecure against active attacks (but may + be desirable for practical reasons in the short term in many + environments). C then computes K = f^x mod p, H = hash(V_C || + V_S || I_C || I_S || K_S || min || n || max || p || g || e || + f || K), and verifies the signature s on H. + + Servers and clients SHOULD support groups with a modulus + + + +Friedl/Provos/Simpson expires in six months [Page 3] + +INTERNET DRAFT July 2003 + + + length of k bits, where 1024 <= k <= 8192. The recommended + values for min and max are 1024 and 8192 respectively. + + Either side MUST NOT send or accept e or f values that are not + in the range [1, p-1]. If this condition is violated, the key + exchange fails. To prevent confinement attacks, they MUST + accept the shared secret K only if 1 < K < p - 1. + + + The server should return the smallest group it knows that is larger + than the size the client requested. If the server does not know a + group that is larger than the client request, then it SHOULD return + the largest group it knows. In all cases, the size of the returned + group SHOULD be at least 1024 bits. + + This is implemented with the following messages. The hash algo- + rithm for computing the exchange hash is defined by the method + name, and is called HASH. The public key algorithm for signing is + negotiated with the KEXINIT messages. + + First, the client sends: + byte SSH_MSG_KEY_DH_GEX_REQUEST + uint32 min, minimal size in bits of an acceptable group + uint32 n, preferred size in bits of the group the server should send + uint32 max, maximal size in bits of an acceptable group + + The server responds with + byte SSH_MSG_KEX_DH_GEX_GROUP + mpint p, safe prime + mpint g, generator for subgroup in GF(p) + + The client responds with: + byte SSH_MSG_KEX_DH_GEX_INIT + mpint e + + The server responds with: + byte SSH_MSG_KEX_DH_GEX_REPLY + string server public host key and certificates (K_S) + mpint f + string signature of H + + The hash H is computed as the HASH hash of the concatenation of the + following: + string V_C, the client's version string (CR and NL excluded) + string V_S, the server's version string (CR and NL excluded) + string I_C, the payload of the client's SSH_MSG_KEXINIT + string I_S, the payload of the server's SSH_MSG_KEXINIT + string K_S, the host key + + + +Friedl/Provos/Simpson expires in six months [Page 4] + +INTERNET DRAFT July 2003 + + + uint32 min, minimal size in bits of an acceptable group + uint32 n, preferred size in bits of the group the server should send + uint32 max, maximal size in bits of an acceptable group + mpint p, safe prime + mpint g, generator for subgroup + mpint e, exchange value sent by the client + mpint f, exchange value sent by the server + mpint K, the shared secret + + This value is called the exchange hash, and it is used to authenti- + cate the key exchange. + + +6. diffie-hellman-group-exchange-sha1 + + The "diffie-hellman-group-exchange-sha1" method specifies Diffie- + Hellman Group and Key Exchange with SHA-1 as HASH. + +7. Summary of Message numbers + + The following message numbers have been defined in this document. + + #define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30 + #define SSH_MSG_KEX_DH_GEX_REQUEST 34 + #define SSH_MSG_KEX_DH_GEX_GROUP 31 + #define SSH_MSG_KEX_DH_GEX_INIT 32 + #define SSH_MSG_KEX_DH_GEX_REPLY 33 + + SSH_MSG_KEX_DH_GEX_REQUEST_OLD is used for backwards compatibility. + Instead of sending "min || n || max", the client only sends "n". + Additionally, the hash is calculated using only "n" instead of "min + || n || max". + + The numbers 30-49 are key exchange specific and may be redefined by + other kex methods. + +8. Security Considerations + + This protocol aims to be simple and uses only well understood prim- + itives. This encourages acceptance by the community and allows for + ease of implementation, which hopefully leads to a more secure sys- + tem. + + The use of multiple moduli inhibits a determined attacker from pre- + calculating moduli exchange values, and discourages dedication of + resources for analysis of any particular modulus. + + It is important to employ only safe primes as moduli. Van Oorshot + + + +Friedl/Provos/Simpson expires in six months [Page 5] + +INTERNET DRAFT July 2003 + + + and Wiener note that using short private exponents with a random + prime modulus p makes the computation of the discrete logarithm + easy [1]. However, they also state that this problem does not + apply to safe primes. + + The least significant bit of the private exponent can be recovered, + when the modulus is a safe prime [2]. However, this is not a prob- + lem, if the size of the private exponent is big enough. Related to + this, Waldvogel and Massey note: When private exponents are chosen + independently and uniformly at random from {0,...,p-2}, the key + entropy is less than 2 bits away from the maximum, lg(p-1) [3]. + +9. Acknowledgments + + The document is derived in part from "SSH Transport Layer Protocol" + by T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen. + + Markku-Juhani Saarinen pointed out that the least significant bit + of the private exponent can be recovered efficiently when using + safe primes and a subgroup with an order divisible by two. + + Bodo Moeller suggested that the server send only one group, reduc- + ing the complexity of the implementation and the amount of data + that needs to be exchanged between client and server. + +10. Bibliography + + + 10.1. Informative References + + + [1] P. C. van Oorschot and M. J. Wiener, On Diffie-Hellman key + agreement with short exponents, In Advances in Cryptology - + EUROCRYPT'96, LNCS 1070, Springer-Verlag, 1996, pp.332-343. + + [2] Alfred J. Menezes, Paul C. van Oorschot, and Scott A. Van- + stone. Handbook of Applied Cryptography. CRC Press, 1996. + + [3] C. P. Waldvogel and J. L. Massey, The probability distribution + of the Diffie-Hellman key, in Proceedings of AUSCRYPT 92, LNCS + 718, Springer- Verlag, 1993, pp. 492-504. + + + + + + + + + + +Friedl/Provos/Simpson expires in six months [Page 6] + +INTERNET DRAFT July 2003 + + + 10.2. Normative References + + + [4] Ylonen, T., et al: "SSH Protocol Architecture", Internet- + Draft, draft-secsh-architecture-07.txt + + [5] Ylonen, T., et al: "SSH Transport Layer Protocol", Internet- + Draft, draft-ietf-secsh-transport-09.txt + + [6] Ylonen, T., et al: "SSH Authentication Protocol", Internet- + Draft, draft-ietf-secsh-userauth-09.txt + + [7] Ylonen, T., et al: "SSH Connection Protocol", Internet-Draft, + draft-ietf-secsh-connect-09.txt + + + +11. Appendix A: Generation of safe primes + + The Handbook of Applied Cryptography [2] lists the following algo- + rithm to generate a k-bit safe prime p. It has been modified so + that 2 is a generator for the multiplicative group mod p. + + 1. Do the following: + 1.1 Select a random (k-1)-bit prime q, so that q mod 12 = 5. + 1.2 Compute p := 2q + 1, and test whether p is prime, (using, e.g. + trial division and the Rabin-Miller test.) + Repeat until p is prime. + + If an implementation uses the OpenSSL libraries, a group consisting + of a 1024-bit safe prime and 2 as generator can be created as fol- + lows: + + DH *d = NULL; + d = DH_generate_parameters(1024, DH_GENERATOR_2, NULL, NULL); + BN_print_fp(stdout, d->p); + + The order of the subgroup generated by 2 is q = p - 1. + + + + + + + + + + + + + +Friedl/Provos/Simpson expires in six months [Page 7] + +INTERNET DRAFT July 2003 + + +12. Author's Address + + Markus Friedl + Ganghoferstr. 7 + 80339 Munich + Germany + + Email: markus@openbsd.org + + Niels Provos + Center for Information Technology Integration + 535 W. William Street + Ann Arbor, MI, 48103 + + Phone: (734) 764-5207 + Email: provos@citi.umich.edu + + William Allen Simpson + DayDreamer + Computer Systems Consulting Services + 1384 Fontaine + Madion Heights, Michigan 48071 + + Email: wsimpson@greendragon.com + + + + + + + + + + + + + + + + + + + + + + + + + + + +Friedl/Provos/Simpson expires in six months [Page 8] + diff --git a/doc/draft-ietf-secsh-dns-04.txt b/doc/draft-ietf-secsh-dns-04.txt new file mode 100644 index 00000000..7667a5e8 --- /dev/null +++ b/doc/draft-ietf-secsh-dns-04.txt @@ -0,0 +1,616 @@ + + +Secure Shell Working Group J. Schlyter +Internet-Draft Carlstedt Research & +Expires: October 1, 2003 Technology + W. Griffin + Network Associates Laboratories + April 2, 2003 + + + Using DNS to securely publish SSH key fingerprints + draft-ietf-secsh-dns-04.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on October 1, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + This document describes a method to verify SSH host keys using + DNSSEC. The document defines a new DNS resource record that contains + a standard SSH key fingerprint. + + + + + + + + + + +Schlyter & Griffin Expires October 1, 2003 [Page 1] + +Internet-Draft DNS and SSH fingerprints April 2003 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. SSH Host Key Verification . . . . . . . . . . . . . . . . . 3 + 2.1 Method . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2.2 Implementation Notes . . . . . . . . . . . . . . . . . . . . 3 + 2.3 Fingerprint Matching . . . . . . . . . . . . . . . . . . . . 4 + 2.4 Authentication . . . . . . . . . . . . . . . . . . . . . . . 4 + 3. The SSHFP Resource Record . . . . . . . . . . . . . . . . . 4 + 3.1 The SSHFP RDATA Format . . . . . . . . . . . . . . . . . . . 4 + 3.1.1 Algorithm Number Specification . . . . . . . . . . . . . . . 5 + 3.1.2 Fingerprint Type Specification . . . . . . . . . . . . . . . 5 + 3.1.3 Fingerprint . . . . . . . . . . . . . . . . . . . . . . . . 5 + 3.2 Presentation Format of the SSHFP RR . . . . . . . . . . . . 6 + 4. Security Considerations . . . . . . . . . . . . . . . . . . 6 + 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . 7 + Normative References . . . . . . . . . . . . . . . . . . . . 8 + Informational References . . . . . . . . . . . . . . . . . . 8 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 8 + A. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 9 + Intellectual Property and Copyright Statements . . . . . . . 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Schlyter & Griffin Expires October 1, 2003 [Page 2] + +Internet-Draft DNS and SSH fingerprints April 2003 + + +1. Introduction + + The SSH [5] protocol provides secure remote login and other secure + network services over an insecure network. The security of the + connection relies on the server authenticating itself to the client. + + Server authentication is normally done by presenting the fingerprint + of an unknown public key to the user for verification. If the user + decides the fingerprint is correct and accepts the key, the key is + saved locally and used for verification for all following + connections. While some security-conscious users verify the + fingerprint out-of-band before accepting the key, many users blindly + accepts the presented key. + + The method described here can provide out-of-band verification by + looking up a fingerprint of the server public key in the DNS [1][2] + and using DNSSEC [4] to verify the lookup. + + In order to distribute the fingerprint using DNS, this document + defines a new DNS resource record to carry the fingerprint. + + Basic understanding of the DNS system [1][2] and the DNS security + extensions [4] is assumed by this document. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [3]. + +2. SSH Host Key Verification + +2.1 Method + + Upon connection to a SSH server, the SSH client MAY look up the SSHFP + resource record(s) for the host it is connecting to. If the + algorithm and fingerprint of the key received from the SSH server + matches the algorithm and fingerprint of one of the SSHFP resource + record(s) returned from DNS, the client MAY accept the identity of + the server. + +2.2 Implementation Notes + + Client implementors SHOULD provide a configurable policy used to + select the order of methods used to verify a host key. This document + defines one method: Fingerprint storage in DNS. Another method + defined in the SSH Architecture [5] uses local files to store keys + for comparison. Other methods that could be defined in the future + might include storing fingerprints in LDAP or other databases. A + configurable policy will allow administrators to determine which + + + +Schlyter & Griffin Expires October 1, 2003 [Page 3] + +Internet-Draft DNS and SSH fingerprints April 2003 + + + methods they want to use and in what order the methods should be + prioritized. This will allow administrators to determine how much + trust they want to place in the different methods. + + One specific scenario for having a configurable policy is where + clients do not use fully qualified host names to connect to servers. + In this scenario, the implementation SHOULD verify the host key + against a local database before verifying the key via the fingerprint + returned from DNS. This would help prevent an attacker from injecting + a DNS search path into the local resolver and forcing the client to + connect to a different host. + +2.3 Fingerprint Matching + + The public key and the SSHFP resource record are matched together by + comparing algorithm number and fingerprint. + + The public key algorithm and the SSHFP algorithm number MUST + match. + + A message digest of the public key, using the message digest + algorithm specified in the SSHFP fingerprint type, MUST match the + SSH FP fingerprint. + + +2.4 Authentication + + A public key verified using this method MUST only be trusted if the + SSHFP resource record (RR) used for verification was authenticated by + a trusted SIG RR. + + Clients that do not validate the DNSSEC signatures themselves MUST + use a secure transport, e.g. TSIG [8], SIG(0) [9] or IPsec [7], + between themselves and the entity performing the signature + validation. + +3. The SSHFP Resource Record + + The SSHFP resource record (RR) is used to store a fingerprint of a + SSH public host key that is associated with a Domain Name System + (DNS) name. + + The RR type code for the SSHFP RR is TBA. + +3.1 The SSHFP RDATA Format + + The RDATA for a SSHFP RR consists of an algorithm number, fingerprint + type and the fingerprint of the public host key. + + + +Schlyter & Griffin Expires October 1, 2003 [Page 4] + +Internet-Draft DNS and SSH fingerprints April 2003 + + + 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | algorithm | fp type | / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ / + / / + / fingerprint / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +3.1.1 Algorithm Number Specification + + This algorithm number octet describes the algorithm of the public + key. The following values are assigned: + + Value Algorithm name + ----- -------------- + 0 reserved + 1 RSA + 2 DSS + + Reserving other types requires IETF consensus. + +3.1.2 Fingerprint Type Specification + + The fingerprint type octet describes the message-digest algorithm + used to calculate the fingerprint of the public key. The following + values are assigned: + + Value Fingerprint type + ----- ---------------- + 0 reserved + 1 SHA-1 + + Reserving other types requires IETF consensus. For interoperability + reasons, as few fingerprint types as possible should be reserved. + The only reason to reserve additional types is to increase security. + +3.1.3 Fingerprint + + The fingerprint is calculated over the public key blob as described + in [6]. + + The message-digest algorithm is presumed to produce an opaque octet + string output which is placed as-is in the RDATA fingerprint field. + + + + + +Schlyter & Griffin Expires October 1, 2003 [Page 5] + +Internet-Draft DNS and SSH fingerprints April 2003 + + +3.2 Presentation Format of the SSHFP RR + + The presentation format of the SSHFP resource record consists of two + numbers (algorithm and fingerprint type) followed by the fingerprint + itself presented in hex, e.g: + + host.example. SSHFP 2 1 123456789abcdef67890123456789abcdef67890 + + +4. Security Considerations + + Currently, the amount of trust a user can realistically place in a + server key is proportional to the amount of attention paid to + verifying that the public key presented actually corresponds to the + private key of the server. If a user accepts a key without verifying + the fingerprint with something learned through a secured channel, the + connection is vulnerable to a man-in-the-middle attack. + + The approach suggested here shifts the burden of key checking from + each user of a machine to the key checking performed by the + administrator of the DNS recursive server used to resolve the host + information. Hopefully, by reducing the number of times that keys + need to be verified by hand, each verification is performed more + completely. Furthermore, by requiring an administrator do the + checking, the result may be more reliable than placing this task in + the hands of an application user. + + The overall security of using SSHFP for SSH host key verification is + dependent on detailed aspects of how verification is done in SSH + implementations. One such aspect is in which order fingerprints are + looked up (e.g. first checking local file and then SSHFP). We note + that in addition to protecting the first-time transfer of host keys, + SSHFP can optionally be used for stronger host key protection. + + If SSHFP is checked first, new SSH host keys may be distributed by + replacing the corresponding SSHFP in DNS. + + If SSH host key verification can be configured to require SSHFP, + we can implement SSH host key revocation by removing the + corresponding SSHFP from DNS. + + As stated in Section 2.2, we recommend that SSH implementors provide + a policy mechanism to control the order of methods used for host key + verification. One specific scenario for having a configurable policy + is where clients use unqualified host names to connect to servers. In + this case, we recommend that SSH implementations check the host key + against a local database before verifying the key via the fingerprint + returned from DNS. This would help prevent an attacker from injecting + + + +Schlyter & Griffin Expires October 1, 2003 [Page 6] + +Internet-Draft DNS and SSH fingerprints April 2003 + + + a DNS search path into the local resolver and forcing the client to + connect to a different host. + + A different approach to solve the DNS search path issue would be for + clients to use a trusted DNS search path, i.e., one not acquired + through DHCP or other autoconfiguration mechanisms. Since there is no + way with current DNS lookup APIs to tell whether a search path is + from a trusted source, the entire client system would need to be + configured with this trusted DNS search path. + + Another dependency is on the implementation of DNSSEC itself. As + stated in Section 2.4, we mandate the use of secure methods for + lookup and that SSHFP RRs are authenticated by trusted SIG RRs. This + is especially important if SSHFP is to be used as a basis for host + key rollover and/or revocation, as described above. + + Since DNSSEC only protects the integrity of the host key fingerprint + after it is signed by the DNS zone administrator, the fingerprint + must be transferred securely from the SSH host administrator to the + DNS zone administrator. This could be done manually between the + administrators or automatically using secure DNS dynamic update [10] + between the SSH server and the nameserver. We note that this is no + different from other key enrollment situations, e.g. a client sending + a certificate request to a certificate authority for signing. + +5. IANA Considerations + + IANA needs to allocate a RR type code for SSHFP from the standard RR + type space (type 44 requested). + + IANA needs to open a new registry for the SSHFP RR type for public + key algorithms. Defined types are: + + 0 is reserved + 1 is RSA + 2 is DSA + + Adding new reservations requires IETF consensus. + + IANA needs to open a new registry for the SSHFP RR type for + fingerprint types. Defined types are: + + 0 is reserved + 1 is SHA-1 + + Adding new reservations requires IETF consensus. + +Normative References + + + +Schlyter & Griffin Expires October 1, 2003 [Page 7] + +Internet-Draft DNS and SSH fingerprints April 2003 + + + [1] Mockapetris, P., "Domain names - concepts and facilities", STD + 13, RFC 1034, November 1987. + + [2] Mockapetris, P., "Domain names - implementation and + specification", STD 13, RFC 1035, November 1987. + + [3] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + [4] Eastlake, D., "Domain Name System Security Extensions", RFC + 2535, March 1999. + + [5] Rinne, T., Ylonen, T., Kivinen, T. and S. Lehtinen, "SSH + Protocol Architecture", draft-ietf-secsh-architecture-13 (work + in progress), September 2002. + + [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Transport Layer Protocol", + draft-ietf-secsh-transport-15 (work in progress), September + 2002. + +Informational References + + [7] Thayer, R., Doraswamy, N. and R. Glenn, "IP Security Document + Roadmap", RFC 2411, November 1998. + + [8] Vixie, P., Gudmundsson, O., Eastlake, D. and B. Wellington, + "Secret Key Transaction Authentication for DNS (TSIG)", RFC + 2845, May 2000. + + [9] Eastlake, D., "DNS Request and Transaction Signatures ( + SIG(0)s)", RFC 2931, September 2000. + + [10] Wellington, B., "Secure Domain Name System (DNS) Dynamic + Update", RFC 3007, November 2000. + + +Authors' Addresses + + Jakob Schlyter + Carlstedt Research & Technology + Stora Badhusgatan 18-20 + Goteborg SE-411 21 + Sweden + + EMail: jakob@crt.se + URI: http://www.crt.se/~jakob/ + + + + +Schlyter & Griffin Expires October 1, 2003 [Page 8] + +Internet-Draft DNS and SSH fingerprints April 2003 + + + Wesley Griffin + Network Associates Laboratories + 15204 Omega Drive Suite 300 + Rockville, MD 20850 + USA + + EMail: wgriffin@tislabs.com + URI: http://www.nailabs.com/ + +Appendix A. Acknowledgements + + The authors gratefully acknowledges, in no particular order, the + contributions of the following persons: + + Martin Fredriksson + + Olafur Gudmundsson + + Edward Lewis + + Bill Sommerfeld + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Schlyter & Griffin Expires October 1, 2003 [Page 9] + +Internet-Draft DNS and SSH fingerprints April 2003 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + + + +Schlyter & Griffin Expires October 1, 2003 [Page 10] + +Internet-Draft DNS and SSH fingerprints April 2003 + + + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Schlyter & Griffin Expires October 1, 2003 [Page 11] + diff --git a/doc/draft-ietf-secsh-filexfer-02.txt b/doc/draft-ietf-secsh-filexfer-02.txt new file mode 100644 index 00000000..45e979e8 --- /dev/null +++ b/doc/draft-ietf-secsh-filexfer-02.txt @@ -0,0 +1,1626 @@ + + +Network Working Group T. Ylonen +Internet-Draft S. Lehtinen +Expires: April 1, 2002 SSH Communications Security Corp + October 2001 + + + SSH File Transfer Protocol + draft-ietf-secsh-filexfer-02.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on April 1, 2002. + +Copyright Notice + + Copyright (C) The Internet Society (2001). All Rights Reserved. + +Abstract + + The SSH File Transfer Protocol provides secure file transfer + functionality over any reliable data stream. It is the standard file + transfer protocol for use with the SSH2 protocol. This document + describes the file transfer protocol and its interface to the SSH2 + protocol suite. + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 1] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Use with the SSH Connection Protocol . . . . . . . . . . . . 4 + 3. General Packet Format . . . . . . . . . . . . . . . . . . . 5 + 4. Protocol Initialization . . . . . . . . . . . . . . . . . . 7 + 5. File Attributes . . . . . . . . . . . . . . . . . . . . . . 8 + 6. Requests From the Client to the Server . . . . . . . . . . . 10 + 6.1 Request Synchronization and Reordering . . . . . . . . . . . 10 + 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . . 11 + 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . . 13 + 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . . 14 + 6.6 Creating and Deleting Directories . . . . . . . . . . . . . 15 + 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . . 15 + 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . . 16 + 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . . 17 + 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . . 18 + 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . . 18 + 7. Responses from the Server to the Client . . . . . . . . . . 20 + 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . . 24 + 9. Security Considerations . . . . . . . . . . . . . . . . . . 25 + 10. Changes from previous protocol versions . . . . . . . . . . 26 + 10.1 Changes between versions 3 and 2 . . . . . . . . . . . . . . 26 + 10.2 Changes between versions 2 and 1 . . . . . . . . . . . . . . 26 + 10.3 Changes between versions 1 and 0 . . . . . . . . . . . . . . 26 + 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . . 27 + References . . . . . . . . . . . . . . . . . . . . . . . . . 28 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 28 + Full Copyright Statement . . . . . . . . . . . . . . . . . . 29 + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 2] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +1. Introduction + + This protocol provides secure file transfer (and more generally file + system access) functionality over a reliable data stream, such as a + channel in the SSH2 protocol [3]. + + This protocol is designed so that it could be used to implement a + secure remote file system service, as well as a secure file transfer + service. + + This protocol assumes that it runs over a secure channel, and that + the server has already authenticated the user at the client end, and + that the identity of the client user is externally available to the + server implementation. + + In general, this protocol follows a simple request-response model. + Each request and response contains a sequence number and multiple + requests may be pending simultaneously. There are a relatively large + number of different request messages, but a small number of possible + response messages. Each request has one or more response messages + that may be returned in result (e.g., a read either returns data or + reports error status). + + The packet format descriptions in this specification follow the + notation presented in the secsh architecture draft.[3]. + + Even though this protocol is described in the context of the SSH2 + protocol, this protocol is general and independent of the rest of the + SSH2 protocol suite. It could be used in a number of different + applications, such as secure file transfer over TLS RFC 2246 [1] and + transfer of management information in VPN applications. + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 3] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +2. Use with the SSH Connection Protocol + + When used with the SSH2 Protocol suite, this protocol is intended to + be used from the SSH Connection Protocol [5] as a subsystem, as + described in section ``Starting a Shell or a Command''. The + subsystem name used with this protocol is "sftp". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 4] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +3. General Packet Format + + All packets transmitted over the secure connection are of the + following format: + + uint32 length + byte type + byte[length - 1] data payload + + That is, they are just data preceded by 32-bit length and 8-bit type + fields. The `length' is the length of the data area, and does not + include the `length' field itself. The format and interpretation of + the data area depends on the packet type. + + All packet descriptions below only specify the packet type and the + data that goes into the data field. Thus, they should be prefixed by + the `length' and `type' fields. + + The maximum size of a packet is in practice determined by the client + (the maximum size of read or write requests that it sends, plus a few + bytes of packet overhead). All servers SHOULD support packets of at + least 34000 bytes (where the packet size refers to the full length, + including the header above). This should allow for reads and writes + of at most 32768 bytes. + + There is no limit on the number of outstanding (non-acknowledged) + requests that the client may send to the server. In practice this is + limited by the buffering available on the data stream and the queuing + performed by the server. If the server's queues are full, it should + not read any more data from the stream, and flow control will prevent + the client from sending more requests. Note, however, that while + there is no restriction on the protocol level, the client's API may + provide a limit in order to prevent infinite queuing of outgoing + requests at the client. + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 5] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + The following values are defined for packet types. + + #define SSH_FXP_INIT 1 + #define SSH_FXP_VERSION 2 + #define SSH_FXP_OPEN 3 + #define SSH_FXP_CLOSE 4 + #define SSH_FXP_READ 5 + #define SSH_FXP_WRITE 6 + #define SSH_FXP_LSTAT 7 + #define SSH_FXP_FSTAT 8 + #define SSH_FXP_SETSTAT 9 + #define SSH_FXP_FSETSTAT 10 + #define SSH_FXP_OPENDIR 11 + #define SSH_FXP_READDIR 12 + #define SSH_FXP_REMOVE 13 + #define SSH_FXP_MKDIR 14 + #define SSH_FXP_RMDIR 15 + #define SSH_FXP_REALPATH 16 + #define SSH_FXP_STAT 17 + #define SSH_FXP_RENAME 18 + #define SSH_FXP_READLINK 19 + #define SSH_FXP_SYMLINK 20 + #define SSH_FXP_STATUS 101 + #define SSH_FXP_HANDLE 102 + #define SSH_FXP_DATA 103 + #define SSH_FXP_NAME 104 + #define SSH_FXP_ATTRS 105 + #define SSH_FXP_EXTENDED 200 + #define SSH_FXP_EXTENDED_REPLY 201 + + Additional packet types should only be defined if the protocol + version number (see Section ``Protocol Initialization'') is + incremented, and their use MUST be negotiated using the version + number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY + packets can be used to implement vendor-specific extensions. See + Section ``Vendor-Specific-Extensions'' for more details. + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 6] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +4. Protocol Initialization + + When the file transfer protocol starts, it first sends a SSH_FXP_INIT + (including its version number) packet to the server. The server + responds with a SSH_FXP_VERSION packet, supplying the lowest of its + own and the client's version number. Both parties should from then + on adhere to particular version of the protocol. + + The SSH_FXP_INIT packet (from client to server) has the following + data: + + uint32 version + + + The SSH_FXP_VERSION packet (from server to client) has the following + data: + + uint32 version + + + The version number of the protocol specified in this document is 3. + The version number should be incremented for each incompatible + revision of this protocol. + + The extension data in the above packets may be empty, or may be a + sequence of + + string extension_name + string extension_data + + pairs (both strings MUST always be present if one is, but the + `extension_data' string may be of zero length). If present, these + strings indicate extensions to the baseline protocol. The + `extension_name' field(s) identify the name of the extension. The + name should be of the form "name@domain", where the domain is the DNS + domain name of the organization defining the extension. Additional + names that are not of this format may be defined later by the IETF. + Implementations MUST silently ignore any extensions whose name they + do not recognize. + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 7] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +5. File Attributes + + A new compound data type is defined for encoding file attributes. It + is basically just a combination of elementary types, but is defined + once because of the non-trivial description of the fields and to + ensure maintainability. + + The same encoding is used both when returning file attributes from + the server and when sending file attributes to the server. When + sending it to the server, the flags field specifies which attributes + are included, and the server will use default values for the + remaining attributes (or will not modify the values of remaining + attributes). When receiving attributes from the server, the flags + specify which attributes are included in the returned data. The + server normally returns all attributes it knows about. + + uint32 flags + uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE + uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS + uint32 atime present only if flag SSH_FILEXFER_ACMODTIME + uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME + uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count + + The `flags' specify which of the fields are present. Those fields + for which the corresponding flag is not set are not present (not + included in the packet). New flags can only be added by incrementing + the protocol version number (or by using the extension mechanism + described below). + + The `size' field specifies the size of the file in bytes. + + The `uid' and `gid' fields contain numeric Unix-like user and group + identifiers, respectively. + + The `permissions' field contains a bit mask of file permissions as + defined by posix [1]. + + The `atime' and `mtime' contain the access and modification times of + the files, respectively. They are represented as seconds from Jan 1, + 1970 in UTC. + + The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 8] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + mechanism for vendor-specific extensions. If the flag is specified, + then the `extended_count' field is present. It specifies the number + of extended_type-extended_data pairs that follow. Each of these + pairs specifies an extended attribute. For each of the attributes, + the extended_type field should be a string of the format + "name@domain", where "domain" is a valid, registered domain name and + "name" identifies the method. The IETF may later standardize certain + names that deviate from this format (e.g., that do not contain the + "@" sign). The interpretation of `extended_data' depends on the + type. Implementations SHOULD ignore extended data fields that they + do not understand. + + Additional fields can be added to the attributes by either defining + additional bits to the flags field to indicate their presence, or by + defining extended attributes for them. The extended attributes + mechanism is recommended for most purposes; additional flags bits + should only be defined by an IETF standards action that also + increments the protocol version number. The use of such new fields + MUST be negotiated by the version number in the protocol exchange. + It is a protocol error if a packet with unsupported protocol bits is + received. + + The flags bits are defined to have the following values: + + #define SSH_FILEXFER_ATTR_SIZE 0x00000001 + #define SSH_FILEXFER_ATTR_UIDGID 0x00000002 + #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 + #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 + #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 9] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +6. Requests From the Client to the Server + + Requests from the client to the server represent the various file + system operations. Each request begins with an `id' field, which is + a 32-bit identifier identifying the request (selected by the client). + The same identifier will be returned in the response to the request. + One possible implementation of it is a monotonically increasing + request sequence number (modulo 2^32). + + Many operations in the protocol operate on open files. The + SSH_FXP_OPEN request can return a file handle (which is an opaque + variable-length string) which may be used to access the file later + (e.g. in a read operation). The client MUST NOT send requests the + server with bogus or closed handles. However, the server MUST + perform adequate checks on the handle in order to avoid security + risks due to fabricated handles. + + This design allows either stateful and stateless server + implementation, as well as an implementation which caches state + between requests but may also flush it. The contents of the file + handle string are entirely up to the server and its design. The + client should not modify or attempt to interpret the file handle + strings. + + The file handle strings MUST NOT be longer than 256 bytes. + +6.1 Request Synchronization and Reordering + + The protocol and implementations MUST process requests relating to + the same file in the order in which they are received. In other + words, if an application submits multiple requests to the server, the + results in the responses will be the same as if it had sent the + requests one at a time and waited for the response in each case. For + example, the server may process non-overlapping read/write requests + to the same file in parallel, but overlapping reads and writes cannot + be reordered or parallelized. However, there are no ordering + restrictions on the server for processing requests from two different + file transfer connections. The server may interleave and parallelize + them at will. + + There are no restrictions on the order in which responses to + outstanding requests are delivered to the client, except that the + server must ensure fairness in the sense that processing of no + request will be indefinitely delayed even if the client is sending + other requests so that there are multiple outstanding requests all + the time. + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 10] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +6.2 File Names + + This protocol represents file names as strings. File names are + assumed to use the slash ('/') character as a directory separator. + + File names starting with a slash are "absolute", and are relative to + the root of the file system. Names starting with any other character + are relative to the user's default directory (home directory). Note + that identifying the user is assumed to take place outside of this + protocol. + + Servers SHOULD interpret a path name component ".." as referring to + the parent directory, and "." as referring to the current directory. + If the server implementation limits access to certain parts of the + file system, it must be extra careful in parsing file names when + enforcing such restrictions. There have been numerous reported + security bugs where a ".." in a path name has allowed access outside + the intended area. + + An empty path name is valid, and it refers to the user's default + directory (usually the user's home directory). + + Otherwise, no syntax is defined for file names by this specification. + Clients should not make any other assumptions; however, they can + splice path name components returned by SSH_FXP_READDIR together + using a slash ('/') as the separator, and that will work as expected. + + It is understood that the lack of well-defined semantics for file + names may cause interoperability problems between clients and servers + using radically different operating systems. However, this approach + is known to work acceptably with most systems, and alternative + approaches that e.g. treat file names as sequences of structured + components are quite complicated. + +6.3 Opening, Creating, and Closing Files + + Files are opened and created using the SSH_FXP_OPEN message, whose + data part is as follows: + + uint32 id + string filename + uint32 pflags + ATTRS attrs + + The `id' field is the request identifier as for all requests. + + The `filename' field specifies the file name. See Section ``File + Names'' for more information. + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 11] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + The `pflags' field is a bitmask. The following bits have been + defined. + + #define SSH_FXF_READ 0x00000001 + #define SSH_FXF_WRITE 0x00000002 + #define SSH_FXF_APPEND 0x00000004 + #define SSH_FXF_CREAT 0x00000008 + #define SSH_FXF_TRUNC 0x00000010 + #define SSH_FXF_EXCL 0x00000020 + + These have the following meanings: + + SSH_FXF_READ + Open the file for reading. + + SSH_FXF_WRITE + Open the file for writing. If both this and SSH_FXF_READ are + specified, the file is opened for both reading and writing. + + SSH_FXF_APPEND + Force all writes to append data at the end of the file. + + SSH_FXF_CREAT + If this flag is specified, then a new file will be created if one + does not already exist (if O_TRUNC is specified, the new file will + be truncated to zero length if it previously exists). + + SSH_FXF_TRUNC + Forces an existing file with the same name to be truncated to zero + length when creating a file by specifying SSH_FXF_CREAT. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + SSH_FXF_EXCL + Causes the request to fail if the named file already exists. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + The `attrs' field specifies the initial attributes for the file. + Default values will be used for those attributes that are not + specified. See Section ``File Attributes'' for more information. + + Regardless the server operating system, the file will always be + opened in "binary" mode (i.e., no translations between different + character sets and newline encodings). + + The response to this message will be either SSH_FXP_HANDLE (if the + operation is successful) or SSH_FXP_STATUS (if the operation fails). + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 12] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + A file is closed by using the SSH_FXP_CLOSE request. Its data field + has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + previously returned in the response to SSH_FXP_OPEN or + SSH_FXP_OPENDIR. The handle becomes invalid immediately after this + request has been sent. + + The response to this request will be a SSH_FXP_STATUS message. One + should note that on some server platforms even a close can fail. + This can happen e.g. if the server operating system caches writes, + and an error occurs while flushing cached writes during the close. + +6.4 Reading and Writing + + Once a file has been opened, it can be read using the SSH_FXP_READ + message, which has the following format: + + uint32 id + string handle + uint64 offset + uint32 len + + where `id' is the request identifier, `handle' is an open file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative + to the beginning of the file from where to start reading, and `len' + is the maximum number of bytes to read. + + In response to this request, the server will read as many bytes as it + can from the file (up to `len'), and return them in a SSH_FXP_DATA + message. If an error occurs or EOF is encountered before reading any + data, the server will respond with SSH_FXP_STATUS. For normal disk + files, it is guaranteed that this will read the specified number of + bytes, or up to end of file. For e.g. device files this may return + fewer bytes than requested. + + Writing to a file is achieved using the SSH_FXP_WRITE message, which + has the following format: + + uint32 id + string handle + uint64 offset + string data + + where `id' is a request identifier, `handle' is a file handle + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 13] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the + beginning of the file where to start writing, and `data' is the data + to be written. + + The write will extend the file if writing beyond the end of the file. + It is legal to write way beyond the end of the file; the semantics + are to write zeroes from the end of the file to the specified offset + and then the data. On most operating systems, such writes do not + allocate disk space but instead leave "holes" in the file. + + The server responds to a write request with a SSH_FXP_STATUS message. + +6.5 Removing and Renaming Files + + Files can be removed using the SSH_FXP_REMOVE message. It has the + following format: + + uint32 id + string filename + + where `id' is the request identifier and `filename' is the name of + the file to be removed. See Section ``File Names'' for more + information. This request cannot be used to remove directories. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + Files (and directories) can be renamed using the SSH_FXP_RENAME + message. Its data is as follows: + + uint32 id + string oldpath + string newpath + + where `id' is the request identifier, `oldpath' is the name of an + existing file or directory, and `newpath' is the new name for the + file or directory. It is an error if there already exists a file + with the name specified by newpath. The server may also fail rename + requests in other situations, for example if `oldpath' and `newpath' + point to different file systems on the server. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 14] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +6.6 Creating and Deleting Directories + + New directories can be created using the SSH_FXP_MKDIR request. It + has the following format: + + uint32 id + string path + ATTRS attrs + + where `id' is the request identifier, `path' and `attrs' specifies + the modifications to be made to its attributes. See Section ``File + Names'' for more information on file names. Attributes are discussed + in more detail in Section ``File Attributes''. specifies the + directory to be created. An error will be returned if a file or + directory with the specified path already exists. The server will + respond to this request with a SSH_FXP_STATUS message. + + Directories can be removed using the SSH_FXP_RMDIR request, which + has the following format: + + uint32 id + string path + + where `id' is the request identifier, and `path' specifies the + directory to be removed. See Section ``File Names'' for more + information on file names. An error will be returned if no directory + with the specified path exists, or if the specified directory is not + empty, or if the path specified a file system object other than a + directory. The server responds to this request with a SSH_FXP_STATUS + message. + +6.7 Scanning Directories + + The files in a directory can be listed using the SSH_FXP_OPENDIR and + SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one + or more file names with full file attributes for each file. The + client should call SSH_FXP_READDIR repeatedly until it has found the + file it is looking for or until the server responds with a + SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if + there are no more files in the directory). The client should then + close the handle using the SSH_FXP_CLOSE request. + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 15] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + The SSH_FXP_OPENDIR opens a directory for reading. It has the + following format: + + uint32 id + string path + + where `id' is the request identifier and `path' is the path name of + the directory to be listed (without any trailing slash). See Section + ``File Names'' for more information on file names. This will return + an error if the path does not specify a directory or if the directory + is not readable. The server will respond to this request with either + a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. + + Once the directory has been successfully opened, files (and + directories) contained in it can be listed using SSH_FXP_READDIR + requests. These are of the format + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to + use an ordinary file handle returned by SSH_FXP_OPEN.) + + The server responds to this request with either a SSH_FXP_NAME or a + SSH_FXP_STATUS message. One or more names may be returned at a time. + Full status information is returned for each name in order to speed + up typical directory listings. + + When the client no longer wishes to read more names from the + directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle + should be closed regardless of whether an error has occurred or not. + +6.8 Retrieving File Attributes + + Very often, file attributes are automatically returned by + SSH_FXP_READDIR. However, sometimes there is need to specifically + retrieve the attributes for a named file. This can be done using the + SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. + + SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT + follows symbolic links on the server, whereas SSH_FXP_LSTAT does not + follow symbolic links. Both have the same format: + + uint32 id + string path + + where `id' is the request identifier, and `path' specifies the file + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 16] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + system object for which status is to be returned. The server + responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. + + SSH_FXP_FSTAT differs from the others in that it returns status + information for an open file (identified by the file handle). Its + format is as follows: + + uint32 id + string handle + + where `id' is the request identifier and `handle' is a file handle + returned by SSH_FXP_OPEN. The server responds to this request with + SSH_FXP_ATTRS or SSH_FXP_STATUS. + +6.9 Setting File Attributes + + File attributes may be modified using the SSH_FXP_SETSTAT and + SSH_FXP_FSETSTAT requests. These requests are used for operations + such as changing the ownership, permissions or access times, as well + as for truncating a file. + + The SSH_FXP_SETSTAT request is of the following format: + + uint32 id + string path + ATTRS attrs + + where `id' is the request identifier, `path' specifies the file + system object (e.g. file or directory) whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. + + An error will be returned if the specified file system object does + not exist or the user does not have sufficient rights to modify the + specified attributes. The server responds to this request with a + SSH_FXP_STATUS message. + + The SSH_FXP_FSETSTAT request modifies the attributes of a file which + is already open. It has the following format: + + uint32 id + string handle + ATTRS attrs + + where `id' is the request identifier, `handle' (MUST be returned by + SSH_FXP_OPEN) identifies the file whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 17] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. The server will respond to this request with + SSH_FXP_STATUS. + +6.10 Dealing with Symbolic links + + The SSH_FXP_READLINK request may be used to read the target of a + symbolic link. It would have a data part as follows: + + uint32 id + string path + + where `id' is the request identifier and `path' specifies the path + name of the symlink to be read. + + The server will respond with a SSH_FXP_NAME packet containing only + one name and a dummy attributes value. The name in the returned + packet contains the target of the link. If an error occurs, the + server may respond with SSH_FXP_STATUS. + + The SSH_FXP_SYMLINK request will create a symbolic link on the + server. It is of the following format + + uint32 id + string linkpath + string targetpath + + where `id' is the request identifier, `linkpath' specifies the path + name of the symlink to be created and `targetpath' specifies the + target of the symlink. The server shall respond with a + SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error + condition. + +6.11 Canonicalizing the Server-Side Path Name + + The SSH_FXP_REALPATH request can be used to have the server + canonicalize any given path name to an absolute path. This is useful + for converting path names containing ".." components or relative + pathnames without a leading slash into absolute paths. The format of + the request is as follows: + + uint32 id + string path + + where `id' is the request identifier and `path' specifies the path + name to be canonicalized. The server will respond with a + SSH_FXP_NAME packet containing only one name and a dummy attributes + value. The name is the returned packet will be in canonical form. + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 18] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + If an error occurs, the server may also respond with SSH_FXP_STATUS. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 19] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +7. Responses from the Server to the Client + + The server responds to the client using one of a few response + packets. All requests can return a SSH_FXP_STATUS response upon + failure. When the operation is successful, any of the responses may + be returned (depending on the operation). If no data needs to be + returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK + status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used + to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR + requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, + SSH_FXP_NAME is used to return one or more file names from a + SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is + used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and + SSH_FXP_FSTAT requests. + + Exactly one response will be returned for each request. Each + response packet contains a request identifier which can be used to + match each response with the corresponding request. Note that it is + legal to have several requests outstanding simultaneously, and the + server is allowed to send responses to them in a different order from + the order in which the requests were sent (the result of their + execution, however, is guaranteed to be as if they had been processed + one at a time in the order in which the requests were sent). + + Response packets are of the same general format as request packets. + Each response packet begins with the request identifier. + + The format of the data portion of the SSH_FXP_STATUS response is as + follows: + + uint32 id + uint32 error/status code + string error message (ISO-10646 UTF-8 [RFC-2279]) + string language tag (as defined in [RFC-1766]) + + where `id' is the request identifier, and `error/status code' + indicates the result of the requested operation. The value SSH_FX_OK + indicates success, and all other values indicate failure. + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 20] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + Currently, the following values are defined (other values may be + defined by future versions of this protocol): + + #define SSH_FX_OK 0 + #define SSH_FX_EOF 1 + #define SSH_FX_NO_SUCH_FILE 2 + #define SSH_FX_PERMISSION_DENIED 3 + #define SSH_FX_FAILURE 4 + #define SSH_FX_BAD_MESSAGE 5 + #define SSH_FX_NO_CONNECTION 6 + #define SSH_FX_CONNECTION_LOST 7 + #define SSH_FX_OP_UNSUPPORTED 8 + + SSH_FX_OK + Indicates successful completion of the operation. + + SSH_FX_EOF + indicates end-of-file condition; for SSH_FX_READ it means that no + more data is available in the file, and for SSH_FX_READDIR it + indicates that no more files are contained in the directory. + + SSH_FX_NO_SUCH_FILE + is returned when a reference is made to a file which should exist + but doesn't. + + SSH_FX_PERMISSION_DENIED + is returned when the authenticated user does not have sufficient + permissions to perform the operation. + + SSH_FX_FAILURE + is a generic catch-all error message; it should be returned if an + error occurs for which there is no more specific error code + defined. + + SSH_FX_BAD_MESSAGE + may be returned if a badly formatted packet or protocol + incompatibility is detected. + + SSH_FX_NO_CONNECTION + is a pseudo-error which indicates that the client has no + connection to the server (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + SSH_FX_CONNECTION_LOST + is a pseudo-error which indicates that the connection to the + server has been lost (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 21] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + SSH_FX_OP_UNSUPPORTED + indicates that an attempt was made to perform an operation which + is not supported for the server (it may be generated locally by + the client if e.g. the version number exchange indicates that a + required feature is not supported by the server, or it may be + returned by the server if the server does not implement an + operation). + + The SSH_FXP_HANDLE response has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is an arbitrary + string that identifies an open file or directory on the server. The + handle is opaque to the client; the client MUST NOT attempt to + interpret or modify it in any way. The length of the handle string + MUST NOT exceed 256 data bytes. + + The SSH_FXP_DATA response has the following format: + + uint32 id + string data + + where `id' is the request identifier, and `data' is an arbitrary byte + string containing the requested data. The data string may be at most + the number of bytes requested in a SSH_FXP_READ request, but may also + be shorter if end of file is reached or if the read is from something + other than a regular file. + + The SSH_FXP_NAME response has the following format: + + uint32 id + uint32 count + repeats count times: + string filename + string longname + ATTRS attrs + + where `id' is the request identifier, `count' is the number of names + returned in this response, and the remaining fields repeat `count' + times (so that all three fields are first included for the first + file, then for the second file, etc). In the repeated part, + `filename' is a file name being returned (for SSH_FXP_READDIR, it + will be a relative name within the directory, without any path + components; for SSH_FXP_REALPATH it will be an absolute path name), + `longname' is an expanded format for the file name, similar to what + is returned by "ls -l" on Unix systems, and `attrs' is the attributes + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 22] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + of the file as described in Section ``File Attributes''. + + The format of the `longname' field is unspecified by this protocol. + It MUST be suitable for use in the output of a directory listing + command (in fact, the recommended operation for a directory listing + command is to simply display this data). However, clients SHOULD NOT + attempt to parse the longname field for file attributes; they SHOULD + use the attrs field instead. + + The recommended format for the longname field is as follows: + + -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer + 1234567890 123 12345678 12345678 12345678 123456789012 + + Here, the first line is sample output, and the second field indicates + widths of the various fields. Fields are separated by spaces. The + first field lists file permissions for user, group, and others; the + second field is link count; the third field is the name of the user + who owns the file; the fourth field is the name of the group that + owns the file; the fifth field is the size of the file in bytes; the + sixth field (which actually may contain spaces, but is fixed to 12 + characters) is the file modification time, and the seventh field is + the file name. Each field is specified to be a minimum of certain + number of character positions (indicated by the second line above), + but may also be longer if the data does not fit in the specified + length. + + The SSH_FXP_ATTRS response has the following format: + + uint32 id + ATTRS attrs + + where `id' is the request identifier, and `attrs' is the returned + file attributes as described in Section ``File Attributes''. + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 23] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +8. Vendor-Specific Extensions + + The SSH_FXP_EXTENDED request provides a generic extension mechanism + for adding vendor-specific commands. The request has the following + format: + + uint32 id + string extended-request + ... any request-specific data ... + + where `id' is the request identifier, and `extended-request' is a + string of the format "name@domain", where domain is an internet + domain name of the vendor defining the request. The rest of the + request is completely vendor-specific, and servers should only + attempt to interpret it if they recognize the `extended-request' + name. + + The server may respond to such requests using any of the response + packets defined in Section ``Responses from the Server to the + Client''. Additionally, the server may also respond with a + SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does + not recognize the `extended-request' name, then the server MUST + respond with SSH_FXP_STATUS with error/status set to + SSH_FX_OP_UNSUPPORTED. + + The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary + extension-specific data from the server to the client. It is of the + following format: + + uint32 id + ... any request-specific data ... + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 24] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +9. Security Considerations + + This protocol assumes that it is run over a secure channel and that + the endpoints of the channel have been authenticated. Thus, this + protocol assumes that it is externally protected from network-level + attacks. + + This protocol provides file system access to arbitrary files on the + server (only constrained by the server implementation). It is the + responsibility of the server implementation to enforce any access + controls that may be required to limit the access allowed for any + particular user (the user being authenticated externally to this + protocol, typically using the SSH User Authentication Protocol [6]. + + Care must be taken in the server implementation to check the validity + of received file handle strings. The server should not rely on them + directly; it MUST check the validity of each handle before relying on + it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 25] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +10. Changes from previous protocol versions + + The SSH File Transfer Protocol has changed over time, before it's + standardization. The following is a description of the incompatible + changes between different versions. + +10.1 Changes between versions 3 and 2 + + o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. + + o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were + added. + + o The SSH_FXP_STATUS message was changed to include fields `error + message' and `language tag'. + + +10.2 Changes between versions 2 and 1 + + o The SSH_FXP_RENAME message was added. + + +10.3 Changes between versions 1 and 0 + + o Implementation changes, no actual protocol changes. + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 26] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +11. Trademark Issues + + "ssh" is a registered trademark of SSH Communications Security Corp + in the United States and/or other countries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 27] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +References + + [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and + P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January + 1999. + + [2] Institute of Electrical and Electronics Engineers, "Information + Technology - Portable Operating System Interface (POSIX) - Part + 1: System Application Program Interface (API) [C Language]", + IEEE Standard 1003.2, 1996. + + [3] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh- + architecture-09 (work in progress), July 2001. + + [4] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh- + architecture-09 (work in progress), July 2001. + + [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-11 + (work in progress), July 2001. + + [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh- + userauth-11 (work in progress), July 2001. + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: ylo@ssh.com + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 28] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2001). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 29] + + + diff --git a/doc/draft-ietf-secsh-filexfer-03.txt b/doc/draft-ietf-secsh-filexfer-03.txt new file mode 100644 index 00000000..83960ae9 --- /dev/null +++ b/doc/draft-ietf-secsh-filexfer-03.txt @@ -0,0 +1,1962 @@ + + + +Secure Shell Working Group J. Galbraith +Internet-Draft VanDyke Software +Expires: April 16, 2003 T. Ylonen + S. Lehtinen + SSH Communications Security Corp + October 16, 2002 + + + SSH File Transfer Protocol + draft-ietf-secsh-filexfer-03.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on April 16, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + The SSH File Transfer Protocol provides secure file transfer + functionality over any reliable data stream. It is the standard file + transfer protocol for use with the SSH2 protocol. This document + describes the file transfer protocol and its interface to the SSH2 + protocol suite. + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 1] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4 + 3. General Packet Format . . . . . . . . . . . . . . . . . . 5 + 4. Protocol Initialization . . . . . . . . . . . . . . . . . 7 + 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 7 + 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 7 + 4.3 Determining Server Newline Convention . . . . . . . . . . 8 + 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 9 + 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 10 + 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 12 + 6. Requests From the Client to the Server . . . . . . . . . . 13 + 6.1 Request Synchronization and Reordering . . . . . . . . . . 13 + 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 14 + 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 14 + 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 17 + 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 18 + 6.6 Creating and Deleting Directories . . . . . . . . . . . . 19 + 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 19 + 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 20 + 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 21 + 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 22 + 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 23 + 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 23 + 7. Responses from the Server to the Client . . . . . . . . . 24 + 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 28 + 9. Security Considerations . . . . . . . . . . . . . . . . . 29 + 10. Changes from previous protocol versions . . . . . . . . . 30 + 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 30 + 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 31 + 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 31 + 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 31 + 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 32 + References . . . . . . . . . . . . . . . . . . . . . . . . 33 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . 33 + Full Copyright Statement . . . . . . . . . . . . . . . . . 35 + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 2] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +1. Introduction + + This protocol provides secure file transfer (and more generally file + system access) functionality over a reliable data stream, such as a + channel in the SSH2 protocol [5]. + + This protocol is designed so that it could be used to implement a + secure remote file system service, as well as a secure file transfer + service. + + This protocol assumes that it runs over a secure channel, and that + the server has already authenticated the user at the client end, and + that the identity of the client user is externally available to the + server implementation. + + In general, this protocol follows a simple request-response model. + Each request and response contains a sequence number and multiple + requests may be pending simultaneously. There are a relatively large + number of different request messages, but a small number of possible + response messages. Each request has one or more response messages + that may be returned in result (e.g., a read either returns data or + reports error status). + + The packet format descriptions in this specification follow the + notation presented in the secsh architecture draft. [5] + + Even though this protocol is described in the context of the SSH2 + protocol, this protocol is general and independent of the rest of the + SSH2 protocol suite. It could be used in a number of different + applications, such as secure file transfer over TLS RFC 2246 [1] and + transfer of management information in VPN applications. + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 3] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +2. Use with the SSH Connection Protocol + + When used with the SSH2 Protocol suite, this protocol is intended to + be used from the SSH Connection Protocol [7] as a subsystem, as + described in section ``Starting a Shell or a Command''. The + subsystem name used with this protocol is "sftp". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 4] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +3. General Packet Format + + All packets transmitted over the secure connection are of the + following format: + + uint32 length + byte type + byte[length - 1] data payload + + That is, they are just data preceded by 32-bit length and 8-bit type + fields. The `length' is the length of the data area, and does not + include the `length' field itself. The format and interpretation of + the data area depends on the packet type. + + All packet descriptions below only specify the packet type and the + data that goes into the data field. Thus, they should be prefixed by + the `length' and `type' fields. + + The maximum size of a packet is in practice determined by the client + (the maximum size of read or write requests that it sends, plus a few + bytes of packet overhead). All servers SHOULD support packets of at + least 34000 bytes (where the packet size refers to the full length, + including the header above). This should allow for reads and writes + of at most 32768 bytes. + + There is no limit on the number of outstanding (non-acknowledged) + requests that the client may send to the server. In practice this is + limited by the buffering available on the data stream and the queuing + performed by the server. If the server's queues are full, it should + not read any more data from the stream, and flow control will prevent + the client from sending more requests. Note, however, that while + there is no restriction on the protocol level, the client's API may + provide a limit in order to prevent infinite queuing of outgoing + requests at the client. + + The following values are defined for packet types. + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 5] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + #define SSH_FXP_INIT 1 + #define SSH_FXP_VERSION 2 + #define SSH_FXP_OPEN 3 + #define SSH_FXP_CLOSE 4 + #define SSH_FXP_READ 5 + #define SSH_FXP_WRITE 6 + #define SSH_FXP_LSTAT 7 + #define SSH_FXP_FSTAT 8 + #define SSH_FXP_SETSTAT 9 + #define SSH_FXP_FSETSTAT 10 + #define SSH_FXP_OPENDIR 11 + #define SSH_FXP_READDIR 12 + #define SSH_FXP_REMOVE 13 + #define SSH_FXP_MKDIR 14 + #define SSH_FXP_RMDIR 15 + #define SSH_FXP_REALPATH 16 + #define SSH_FXP_STAT 17 + #define SSH_FXP_RENAME 18 + #define SSH_FXP_READLINK 19 + #define SSH_FXP_SYMLINK 20 + + #define SSH_FXP_STATUS 101 + #define SSH_FXP_HANDLE 102 + #define SSH_FXP_DATA 103 + #define SSH_FXP_NAME 104 + #define SSH_FXP_ATTRS 105 + + #define SSH_FXP_EXTENDED 200 + #define SSH_FXP_EXTENDED_REPLY 201 + + RESERVED_FOR_EXTENSIONS 210-255 + + Additional packet types should only be defined if the protocol + version number (see Section ``Protocol Initialization'') is + incremented, and their use MUST be negotiated using the version + number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY + packets can be used to implement vendor-specific extensions. See + Section ``Vendor-Specific-Extensions'' for more details. + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 6] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +4. Protocol Initialization + + When the file transfer protocol starts, the client first sends a + SSH_FXP_INIT (including its version number) packet to the server. + The server responds with a SSH_FXP_VERSION packet, supplying the + lowest of its own and the client's version number. Both parties + should from then on adhere to particular version of the protocol. + + The version number of the protocol specified in this document is 4. + The version number should be incremented for each incompatible + revision of this protocol. + +4.1 Client Initialization + + The SSH_FXP_INIT packet (from client to server) has the following + data: + + uint32 version + + Version 3 of this protocol allowed clients to include extensions in + the SSH_FXP_INIT packet; however, this can cause interoperability + problems with version 1 and version 2 servers because the client must + send this packet before knowing the servers version. + + In this version of the protocol, clients MUST use the + SSH_FXP_EXTENDED packet to send extensions to the server after + version exchange has completed. Clients MUST NOT include extensions + in the version packet. This will prevent interoperability problems + with older servers + +4.2 Server Initialization + + The SSH_FXP_VERSION packet (from server to client) has the following + data: + + uint32 version + + + 'version' is the lower of the protocol version supported by the + server and the version number received from the client. + + The extension data may be empty, or may be a sequence of + + string extension_name + string extension_data + + pairs (both strings MUST always be present if one is, but the + `extension_data' string may be of zero length). If present, these + + + +Galbraith, et al. Expires April 16, 2003 [Page 7] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + strings indicate extensions to the baseline protocol. The + `extension_name' field(s) identify the name of the extension. The + name should be of the form "name@domain", where the domain is the DNS + domain name of the organization defining the extension. Additional + names that are not of this format may be defined later by the IETF. + Implementations MUST silently ignore any extensions whose name they + do not recognize. + +4.3 Determining Server Newline Convention + + In order to correctly process text files in a cross platform + compatible way, the newline convention must be converted from that of + the server to that of the client, or, during an upload, from that of + the client to that of the server. + + Versions 3 and prior of this protocol made no provisions for + processing text files. Many clients implemented some sort of + conversion algorithm, but without either a 'canonical' on the wire + format or knowledge of the servers newline convention, correct + conversion was not always possible. + + Starting with Version 4, the SSH_FXF_TEXT file open flag (Section + 6.3) makes it possible to request that the server translate a file to + a 'canonical' on the wire format. This format uses \r\n as the line + separator. + + Servers for systems using multiple newline characters (for example, + Mac OS X or VMS) or systems using counted records, MUST translate to + the canonical form. + + However, to ease the burden of implementation on servers that use a + single, simple separator sequence, the following extension allows the + canonical format to be changed. + + string "newline" + string new-canonical-separator (usually "\r" or "\n" or "\r\n") + + All clients MUST support this extension. + + When processing text files, clients SHOULD NOT translate any + character or sequence that is not an exact match of the servers + newline separator. + + In particular, if the newline sequence being used is the canonical + "\r\n" sequence, a lone \r or a lone \n SHOULD be written through + without change. + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 8] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +5. File Attributes + + A new compound data type is defined for encoding file attributes. + The same encoding is used both when returning file attributes from + the server and when sending file attributes to the server. When + sending it to the server, the flags field specifies which attributes + are included, and the server will use default values for the + remaining attributes (or will not modify the values of remaining + attributes). When receiving attributes from the server, the flags + specify which attributes are included in the returned data. The + server normally returns all attributes it knows about. + + uint32 flags + byte type always present + uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE + string owner present only if flag SSH_FILEXFER_ATTR_OWNERGROUP + string group present only if flag SSH_FILEXFER_ATTR_OWNERGROUP + uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS + uint32 atime present only if flag SSH_FILEXFER_ATTR_ACCESSTIME + uint32 createtime present only if flag SSH_FILEXFER_ATTR_CREATETIME + uint32 mtime present only if flag SSH_FILEXFER_ATTR_MODIFYTIME + string acl present only if flag SSH_FILEXFER_ATTR_ACL + uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count + + +5.1 Flags + + The `flags' specify which of the fields are present. Those fields + for which the corresponding flag is not set are not present (not + included in the packet). New flags can only be added by incrementing + the protocol version number (or by using the extension mechanism + described below). + + The flags bits are defined to have the following values: + + #define SSH_FILEXFER_ATTR_SIZE 0x00000001 + #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 + #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 + #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 + #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 + #define SSH_FILEXFER_ATTR_ACL 0x00000040 + #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 + #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 + + + + +Galbraith, et al. Expires April 16, 2003 [Page 9] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + In previous versions of this protocol flags value 0x00000002 was + SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP + was given a new value in order to ease implementation burden. + 0x00000002 MUST NOT appear in the mask. Some future version of this + protocol may reuse flag 0x00000002. + +5.2 Type + + The type field is always present. The following types are defined: + + #define SSH_FILEXFER_TYPE_REGULAR 1 + #define SSH_FILEXFER_TYPE_DIRECTORY 2 + #define SSH_FILEXFER_TYPE_SYMLINK 3 + #define SSH_FILEXFER_TYPE_SPECIAL 4 + #define SSH_FILEXFER_TYPE_UNKNOWN 5 + + On a POSIX system, these values would be derived from the permission + field. + +5.3 Size + + The `size' field specifies the size of the file on disk, in bytes. + If it is present during file creation, it should be considered a hint + as to the files eventual size. + + Files opened with the SSH_FXF_TEXT flag may have a size that is + greater or less than the value of the size field. + +5.4 Owner and Group + + The `owner' and `group' fields are represented as UTF-8 strings; this + is the form used by NFS v4. See NFS version 4 Protocol. [3] The + following text is selected quotations from section 5.6. + + To avoid a representation that is tied to a particular underlying + implementation at the client or server, the use of UTF-8 strings has + been chosen. The string should be of the form user@dns_domain". + This will allow for a client and server that do not use the same + local representation the ability to translate to a common syntax that + can be interpreted by both. In the case where there is no + translation available to the client or server, the attribute value + must be constructed without the "@". Therefore, the absence of the @ + from the owner or owner_group attribute signifies that no translation + was available and the receiver of the attribute should not place any + special meaning with the attribute value. Even though the attribute + value can not be translated, it may still be useful. In the case of + a client, the attribute string may be used for local display of + ownership. + + + +Galbraith, et al. Expires April 16, 2003 [Page 10] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +5.5 Permissions + + The `permissions' field contains a bit mask of file permissions as + defined by POSIX [1]. + +5.6 Times + + The 'atime', 'createtime', and 'mtime' contain the access, creation, + and modification times of the files, respectively. They are + represented as seconds from Jan 1, 1970 in UTC. + +5.7 ACL + + The 'ACL' field contains an ACL similar to that defined in section + 5.9 of NFS version 4 Protocol [3]. + + uint32 ace-count + + repeated ace-count time: + uint32 ace-type + uint32 ace-flag + uint32 ace-mask + string who [UTF-8] + + ace-type is one of the following four values (taken from NFS Version + 4 Protocol [3]: + + const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000; + const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001; + const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002; + const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003; + + ace-flag is a combination of the following flag values. See NFS + Version 4 Protocol [3] section 5.9.2: + + const ACE4_FILE_INHERIT_ACE = 0x00000001; + const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002; + const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004; + const ACE4_INHERIT_ONLY_ACE = 0x00000008; + const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010; + const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020; + const ACE4_IDENTIFIER_GROUP = 0x00000040; + + ace-mask is any combination of the following flags (taken from NFS + Version 4 Protocol [3] section 5.9.3: + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 11] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + const ACE4_READ_DATA = 0x00000001; + const ACE4_LIST_DIRECTORY = 0x00000001; + const ACE4_WRITE_DATA = 0x00000002; + const ACE4_ADD_FILE = 0x00000002; + const ACE4_APPEND_DATA = 0x00000004; + const ACE4_ADD_SUBDIRECTORY = 0x00000004; + const ACE4_READ_NAMED_ATTRS = 0x00000008; + const ACE4_WRITE_NAMED_ATTRS = 0x00000010; + const ACE4_EXECUTE = 0x00000020; + const ACE4_DELETE_CHILD = 0x00000040; + const ACE4_READ_ATTRIBUTES = 0x00000080; + const ACE4_WRITE_ATTRIBUTES = 0x00000100; + const ACE4_DELETE = 0x00010000; + const ACE4_READ_ACL = 0x00020000; + const ACE4_WRITE_ACL = 0x00040000; + const ACE4_WRITE_OWNER = 0x00080000; + const ACE4_SYNCHRONIZE = 0x00100000; + + who is a UTF-8 string of the form described in 'Owner and Group' + (Section 5.4) + +5.8 Extended attributes + + The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension + mechanism for vendor-specific extensions. If the flag is specified, + then the `extended_count' field is present. It specifies the number + of extended_type-extended_data pairs that follow. Each of these + pairs specifies an extended attribute. For each of the attributes, + the extended_type field should be a string of the format + "name@domain", where "domain" is a valid, registered domain name and + "name" identifies the method. The IETF may later standardize certain + names that deviate from this format (e.g., that do not contain the + "@" sign). The interpretation of `extended_data' depends on the + type. Implementations SHOULD ignore extended data fields that they + do not understand. + + Additional fields can be added to the attributes by either defining + additional bits to the flags field to indicate their presence, or by + defining extended attributes for them. The extended attributes + mechanism is recommended for most purposes; additional flags bits + should only be defined by an IETF standards action that also + increments the protocol version number. The use of such new fields + MUST be negotiated by the version number in the protocol exchange. + It is a protocol error if a packet with unsupported protocol bits is + received. + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 12] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +6. Requests From the Client to the Server + + Requests from the client to the server represent the various file + system operations. Each request begins with an `id' field, which is + a 32-bit identifier identifying the request (selected by the client). + The same identifier will be returned in the response to the request. + One possible implementation is a monotonically increasing request + sequence number (modulo 2^32). + + Many operations in the protocol operate on open files. The + SSH_FXP_OPEN request can return a file handle (which is an opaque + variable-length string) which may be used to access the file later + (e.g. in a read operation). The client MUST NOT send requests the + server with bogus or closed handles. However, the server MUST + perform adequate checks on the handle in order to avoid security + risks due to fabricated handles. + + This design allows either stateful and stateless server + implementation, as well as an implementation which caches state + between requests but may also flush it. The contents of the file + handle string are entirely up to the server and its design. The + client should not modify or attempt to interpret the file handle + strings. + + The file handle strings MUST NOT be longer than 256 bytes. + +6.1 Request Synchronization and Reordering + + The protocol and implementations MUST process requests relating to + the same file in the order in which they are received. In other + words, if an application submits multiple requests to the server, the + results in the responses will be the same as if it had sent the + requests one at a time and waited for the response in each case. For + example, the server may process non-overlapping read/write requests + to the same file in parallel, but overlapping reads and writes cannot + be reordered or parallelized. However, there are no ordering + restrictions on the server for processing requests from two different + file transfer connections. The server may interleave and parallelize + them at will. + + There are no restrictions on the order in which responses to + outstanding requests are delivered to the client, except that the + server must ensure fairness in the sense that processing of no + request will be indefinitely delayed even if the client is sending + other requests so that there are multiple outstanding requests all + the time. + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 13] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +6.2 File Names + + This protocol represents file names as strings. File names are + assumed to use the slash ('/') character as a directory separator. + + File names starting with a slash are "absolute", and are relative to + the root of the file system. Names starting with any other character + are relative to the user's default directory (home directory). Note + that identifying the user is assumed to take place outside of this + protocol. + + Servers SHOULD interpret a path name component ".." as referring to + the parent directory, and "." as referring to the current directory. + If the server implementation limits access to certain parts of the + file system, it must be extra careful in parsing file names when + enforcing such restrictions. There have been numerous reported + security bugs where a ".." in a path name has allowed access outside + the intended area. + + An empty path name is valid, and it refers to the user's default + directory (usually the user's home directory). + + Otherwise, no syntax is defined for file names by this specification. + Clients should not make any other assumptions; however, they can + splice path name components returned by SSH_FXP_READDIR together + using a slash ('/') as the separator, and that will work as expected. + + In order to comply with IETF Policy on Character Sets and Languages + [2], all filenames are to be encoded in UTF-8. The shortest valid + UTF-8 encoding of the UNICODE data MUST be used. The server is + responsible for converting the UNICODE data to whatever canonical + form it requires. + + For example, if the server requires that precomposed characters + always be used, the server MUST NOT assume the filename as sent by + the client has this attribute, but must do this normalization itself. + + It is understood that the lack of well-defined semantics for file + names may cause interoperability problems between clients and servers + using radically different operating systems. However, this approach + is known to work acceptably with most systems, and alternative + approaches that e.g. treat file names as sequences of structured + components are quite complicated. + +6.3 Opening, Creating, and Closing Files + + Files are opened and created using the SSH_FXP_OPEN message, whose + data part is as follows: + + + +Galbraith, et al. Expires April 16, 2003 [Page 14] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + uint32 id + string filename [UTF-8] + uint32 pflags + ATTRS attrs + + The `id' field is the request identifier as for all requests. + + The `filename' field specifies the file name. See Section ``File + Names'' for more information. + + The `pflags' field is a bitmask. The following bits have been + defined. + + #define SSH_FXF_READ 0x00000001 + #define SSH_FXF_WRITE 0x00000002 + #define SSH_FXF_APPEND 0x00000004 + #define SSH_FXF_CREAT 0x00000008 + #define SSH_FXF_TRUNC 0x00000010 + #define SSH_FXF_EXCL 0x00000020 + #define SSH_FXF_TEXT 0x00000040 + + These have the following meanings: + + SSH_FXF_READ + Open the file for reading. + + SSH_FXF_WRITE + Open the file for writing. If both this and SSH_FXF_READ are + specified, the file is opened for both reading and writing. + + SSH_FXF_APPEND + Force all writes to append data at the end of the file. The + offset parameter to write will be ignored. + + SSH_FXF_CREAT + If this flag is specified, then a new file will be created if one + does not already exist (if O_TRUNC is specified, the new file will + be truncated to zero length if it previously exists). + + SSH_FXF_TRUNC + Forces an existing file with the same name to be truncated to zero + length when creating a file by specifying SSH_FXF_CREAT. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + SSH_FXF_EXCL + Causes the request to fail if the named file already exists. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + + + +Galbraith, et al. Expires April 16, 2003 [Page 15] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + SSH_FXF_TEXT + Indicates that the server should treat the file as text and + convert it to the canonical newline convention in use. (See + Determining Server Newline Convention. (Section 4.3) + + When a file is opened with the FXF_TEXT flag, the offset field in + both the read and write function are ignored. + + Servers MUST correctly process multiple parallel reads and writes + correctly in this mode. Naturally, it is permissible for them to + do this by serializing the requests. It would not be possible for + a client to reliably detect a server that does not implement + parallel writes in time to prevent damage. + + Clients SHOULD use the SSH_FXF_APPEND flag to append data to a + text file rather then using write with a calculated offset. + + To support seeks on text file the following SSH_FXP_EXTENDED + packet is defined. + + + + string "text-seek" + string file-handle + uint64 line-number + + line-number is the index of the line number to seek to, where byte + 0 in the file is line number 0, and the byte directly following + the first newline sequence in the file is line number 1 and so on. + + The response to a "text-seek" request is an SSH_FXP_STATUS + message. + + An attempt to seek past the end-of-file should result in a + SSH_FX_EOF status. + + Servers SHOULD support at least one "text-seek" in order to + support resume. However, a client MUST be prepared to receive + SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation. + The client can then try a fall-back strategy, if it has one. + + Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned + for read or write operations that are not sequential. + + The `attrs' field specifies the initial attributes for the file. + Default values will be used for those attributes that are not + specified. See Section ``File Attributes'' for more information. + + + + +Galbraith, et al. Expires April 16, 2003 [Page 16] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + The response to this message will be either SSH_FXP_HANDLE (if the + operation is successful) or SSH_FXP_STATUS (if the operation fails). + + A file is closed by using the SSH_FXP_CLOSE request. Its data field + has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + previously returned in the response to SSH_FXP_OPEN or + SSH_FXP_OPENDIR. The handle becomes invalid immediately after this + request has been sent. + + The response to this request will be a SSH_FXP_STATUS message. One + should note that on some server platforms even a close can fail. + This can happen e.g. if the server operating system caches writes, + and an error occurs while flushing cached writes during the close. + +6.4 Reading and Writing + + Once a file has been opened, it can be read using the SSH_FXP_READ + message, which has the following format: + + uint32 id + string handle + uint64 offset + uint32 len + + where `id' is the request identifier, `handle' is an open file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative + to the beginning of the file from where to start reading, and `len' + is the maximum number of bytes to read. + + In response to this request, the server will read as many bytes as it + can from the file (up to `len'), and return them in a SSH_FXP_DATA + message. If an error occurs or EOF is encountered before reading any + data, the server will respond with SSH_FXP_STATUS. For normal disk + files, it is guaranteed that this will read the specified number of + bytes, or up to end of file. For e.g. device files this may return + fewer bytes than requested. + + Writing to a file is achieved using the SSH_FXP_WRITE message, which + has the following format: + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 17] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + uint32 id + string handle + uint64 offset + string data + + where `id' is a request identifier, `handle' is a file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the + beginning of the file where to start writing, and `data' is the data + to be written. + + The write will extend the file if writing beyond the end of the file. + It is legal to write way beyond the end of the file; the semantics + are to write zeroes from the end of the file to the specified offset + and then the data. On most operating systems, such writes do not + allocate disk space but instead leave "holes" in the file. + + The server responds to a write request with a SSH_FXP_STATUS message. + +6.5 Removing and Renaming Files + + Files can be removed using the SSH_FXP_REMOVE message. It has the + following format: + + uint32 id + string filename [UTF-8] + + where `id' is the request identifier and `filename' is the name of + the file to be removed. See Section ``File Names'' for more + information. This request cannot be used to remove directories. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + Files (and directories) can be renamed using the SSH_FXP_RENAME + message. Its data is as follows: + + uint32 id + string oldpath [UTF-8] + string newpath [UTF-8] + + where `id' is the request identifier, `oldpath' is the name of an + existing file or directory, and `newpath' is the new name for the + file or directory. It is an error if there already exists a file + with the name specified by newpath. The server may also fail rename + requests in other situations, for example if `oldpath' and `newpath' + point to different file systems on the server. + + The server will respond to this request with a SSH_FXP_STATUS + + + +Galbraith, et al. Expires April 16, 2003 [Page 18] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + message. + +6.6 Creating and Deleting Directories + + New directories can be created using the SSH_FXP_MKDIR request. It + has the following format: + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier. + + `path' specifies the directory to be created. See Section ``File + Names'' for more information on file names. + + `attrs' specifies the attributes that should be applied to it upon + creation. Attributes are discussed in more detail in Section ``File + Attributes''. + + The server will respond to this request with a SSH_FXP_STATUS + message. If a file or directory with the specified path already + exists, an error will be returned. + + Directories can be removed using the SSH_FXP_RMDIR request, which has + the following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier, and `path' specifies the + directory to be removed. See Section ``File Names'' for more + information on file names. + + The server responds to this request with a SSH_FXP_STATUS message. + Errors may be returned from this operation for various reasons, + including, but not limited to, the path does not exist, the path does + not refer to a directory object, the directory is not empty, or the + user has insufficient access or permission to perform the requested + operation. + +6.7 Scanning Directories + + The files in a directory can be listed using the SSH_FXP_OPENDIR and + SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one + or more file names with full file attributes for each file. The + client should call SSH_FXP_READDIR repeatedly until it has found the + file it is looking for or until the server responds with a + + + +Galbraith, et al. Expires April 16, 2003 [Page 19] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if + there are no more files in the directory). The client should then + close the handle using the SSH_FXP_CLOSE request. + + The SSH_FXP_OPENDIR opens a directory for reading. It has the + following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' is the path name of + the directory to be listed (without any trailing slash). See Section + ``File Names'' for more information on file names. This will return + an error if the path does not specify a directory or if the directory + is not readable. The server will respond to this request with either + a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. + + Once the directory has been successfully opened, files (and + directories) contained in it can be listed using SSH_FXP_READDIR + requests. These are of the format + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to + use an ordinary file handle returned by SSH_FXP_OPEN.) + + The server responds to this request with either a SSH_FXP_NAME or a + SSH_FXP_STATUS message. One or more names may be returned at a time. + Full status information is returned for each name in order to speed + up typical directory listings. + + If there are no more names available to be read, the server MUST + respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF. + + When the client no longer wishes to read more names from the + directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle + should be closed regardless of whether an error has occurred or not. + +6.8 Retrieving File Attributes + + Very often, file attributes are automatically returned by + SSH_FXP_READDIR. However, sometimes there is need to specifically + retrieve the attributes for a named file. This can be done using the + SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. + + SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT + + + +Galbraith, et al. Expires April 16, 2003 [Page 20] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + follows symbolic links on the server, whereas SSH_FXP_LSTAT does not + follow symbolic links. Both have the same format: + + uint32 id + string path [UTF-8] + uint32 flags + + where `id' is the request identifier, and `path' specifies the file + system object for which status is to be returned. The server + responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. + + The flags field specify the attribute flags in which the client has + particular interest. This is a hint to the server. For example, + because retrieving owner / group and acl information can be an + expensive operation under some operating systems, the server may + choose not to retrieve this information unless the client expresses a + specific interest in it. + + The client has no guarantee the server will provide all the fields + that it has expressed an interest in. + + SSH_FXP_FSTAT differs from the others in that it returns status + information for an open file (identified by the file handle). Its + format is as follows: + + uint32 id + string handle + uint32 flags + + where `id' is the request identifier and `handle' is a file handle + returned by SSH_FXP_OPEN. The server responds to this request with + SSH_FXP_ATTRS or SSH_FXP_STATUS. + +6.9 Setting File Attributes + + File attributes may be modified using the SSH_FXP_SETSTAT and + SSH_FXP_FSETSTAT requests. These requests are used for operations + such as changing the ownership, permissions or access times, as well + as for truncating a file. + + The SSH_FXP_SETSTAT request is of the following format: + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `path' specifies the file + system object (e.g. file or directory) whose attributes are to be + + + +Galbraith, et al. Expires April 16, 2003 [Page 21] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. + + An error will be returned if the specified file system object does + not exist or the user does not have sufficient rights to modify the + specified attributes. The server responds to this request with a + SSH_FXP_STATUS message. + + The SSH_FXP_FSETSTAT request modifies the attributes of a file which + is already open. It has the following format: + + uint32 id + string handle + ATTRS attrs + + where `id' is the request identifier, `handle' (MUST be returned by + SSH_FXP_OPEN) identifies the file whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. The server will respond to this request with + SSH_FXP_STATUS. + +6.10 Dealing with Symbolic links + + The SSH_FXP_READLINK request may be used to read the target of a + symbolic link. It would have a data part as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name of the symlink to be read. + + The server will respond with a SSH_FXP_NAME packet containing only + one name and a dummy attributes value. The name in the returned + packet contains the target of the link. If an error occurs, the + server may respond with SSH_FXP_STATUS. + + The SSH_FXP_SYMLINK request will create a symbolic link on the + server. It is of the following format + + uint32 id + string linkpath [UTF-8] + string targetpath [UTF-8] + + where `id' is the request identifier, `linkpath' specifies the path + name of the symlink to be created and `targetpath' specifies the + + + +Galbraith, et al. Expires April 16, 2003 [Page 22] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + target of the symlink. The server shall respond with a + SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error + condition. + +6.11 Canonicalizing the Server-Side Path Name + + The SSH_FXP_REALPATH request can be used to have the server + canonicalize any given path name to an absolute path. This is useful + for converting path names containing ".." components or relative + pathnames without a leading slash into absolute paths. The format of + the request is as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name to be canonicalized. The server will respond with a + SSH_FXP_NAME packet containing the name in canonical form and a dummy + attributes value. If an error occurs, the server may also respond + with SSH_FXP_STATUS. + +6.11.1 Best practice for dealing with paths + + The client SHOULD treat the results of SSH_FXP_REALPATH as a + canonical absolute path, even if the path does not appear to be + absolute. A client that use REALPATH(".") and treats the result as + absolute, even if there is no leading slash, will continue to + function correctly, even when talking to a Windows NT or VMS style + system, where absolute paths may not begin with a slash. + + For example, if the client wishes to change directory up, and the + server has returned "c:/x/y/z" from REALPATH, the client SHOULD use + "c:/x/y/z/..". + + As a second example, if the client wishes to open the file "x.txt" in + the current directory, and server has returned "dka100:/x/y/z" as the + canonical path of the directory, the client SHOULD open "dka100:/x/y/ + z/x.txt" + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 23] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +7. Responses from the Server to the Client + + The server responds to the client using one of a few response + packets. All requests can return a SSH_FXP_STATUS response upon + failure. When the operation is successful, any of the responses may + be returned (depending on the operation). If no data needs to be + returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK + status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used + to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR + requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, + SSH_FXP_NAME is used to return one or more file names from a + SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is + used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and + SSH_FXP_FSTAT requests. + + Exactly one response will be returned for each request. Each + response packet contains a request identifier which can be used to + match each response with the corresponding request. Note that it is + legal to have several requests outstanding simultaneously, and the + server is allowed to send responses to them in a different order from + the order in which the requests were sent (the result of their + execution, however, is guaranteed to be as if they had been processed + one at a time in the order in which the requests were sent). + + Response packets are of the same general format as request packets. + Each response packet begins with the request identifier. + + The format of the data portion of the SSH_FXP_STATUS response is as + follows: + + uint32 id + uint32 error/status code + string error message (ISO-10646 UTF-8 [RFC-2279]) + string language tag (as defined in [RFC-1766]) + + where `id' is the request identifier, and `error/status code' + indicates the result of the requested operation. The value SSH_FX_OK + indicates success, and all other values indicate failure. + + Currently, the following values are defined (other values may be + defined by future versions of this protocol): + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 24] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + #define SSH_FX_OK 0 + #define SSH_FX_EOF 1 + #define SSH_FX_NO_SUCH_FILE 2 + #define SSH_FX_PERMISSION_DENIED 3 + #define SSH_FX_FAILURE 4 + #define SSH_FX_BAD_MESSAGE 5 + #define SSH_FX_NO_CONNECTION 6 + #define SSH_FX_CONNECTION_LOST 7 + #define SSH_FX_OP_UNSUPPORTED 8 + #define SSH_FX_INVALID_HANDLE 9 + #define SSH_FX_NO_SUCH_PATH 10 + #define SSH_FX_FILE_ALREADY_EXISTS 11 + #define SSH_FX_WRITE_PROTECT 12 + + SSH_FX_OK + Indicates successful completion of the operation. + + SSH_FX_EOF + indicates end-of-file condition; for SSH_FX_READ it means that no + more data is available in the file, and for SSH_FX_READDIR it + indicates that no more files are contained in the directory. + + SSH_FX_NO_SUCH_FILE + is returned when a reference is made to a file which does not + exist. + + SSH_FX_PERMISSION_DENIED + is returned when the authenticated user does not have sufficient + permissions to perform the operation. + + SSH_FX_FAILURE + is a generic catch-all error message; it should be returned if an + error occurs for which there is no more specific error code + defined. + + SSH_FX_BAD_MESSAGE + may be returned if a badly formatted packet or protocol + incompatibility is detected. + + SSH_FX_NO_CONNECTION + is a pseudo-error which indicates that the client has no + connection to the server (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + SSH_FX_CONNECTION_LOST + is a pseudo-error which indicates that the connection to the + server has been lost (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + + +Galbraith, et al. Expires April 16, 2003 [Page 25] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + SSH_FX_OP_UNSUPPORTED + indicates that an attempt was made to perform an operation which + is not supported for the server (it may be generated locally by + the client if e.g. the version number exchange indicates that a + required feature is not supported by the server, or it may be + returned by the server if the server does not implement an + operation). + + SSH_FX_INVALID_HANDLE + The handle value was invalid. + + SSH_FX_NO_SUCH_PATH + The file path does not exist or is invalid. + + SSH_FX_FILE_ALREADY_EXISTS + The file already exists. + + SSH_FX_WRITE_PROTECT + The file is on read only media, or the media is write protected. + + The SSH_FXP_HANDLE response has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is an arbitrary + string that identifies an open file or directory on the server. The + handle is opaque to the client; the client MUST NOT attempt to + interpret or modify it in any way. The length of the handle string + MUST NOT exceed 256 data bytes. + + The SSH_FXP_DATA response has the following format: + + uint32 id + string data + + where `id' is the request identifier, and `data' is an arbitrary byte + string containing the requested data. The data string may be at most + the number of bytes requested in a SSH_FXP_READ request, but may also + be shorter if end of file is reached or if the read is from something + other than a regular file. + + The SSH_FXP_NAME response has the following format: + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 26] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + uint32 id + uint32 count + repeats count times: + string filename [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `count' is the number of names + returned in this response, and the remaining fields repeat `count' + times (so that all three fields are first included for the first + file, then for the second file, etc). In the repeated part, + `filename' is a file name being returned (for SSH_FXP_READDIR, it + will be a relative name within the directory, without any path + components; for SSH_FXP_REALPATH it will be an absolute path name), + and `attrs' is the attributes of the file as described in Section + ``File Attributes''. + + The SSH_FXP_ATTRS response has the following format: + + uint32 id + ATTRS attrs + + where `id' is the request identifier, and `attrs' is the returned + file attributes as described in Section ``File Attributes''. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 27] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +8. Vendor-Specific Extensions + + The SSH_FXP_EXTENDED request provides a generic extension mechanism + for adding vendor-specific commands. The request has the following + format: + + uint32 id + string extended-request + ... any request-specific data ... + + where `id' is the request identifier, and `extended-request' is a + string of the format "name@domain", where domain is an internet + domain name of the vendor defining the request. The rest of the + request is completely vendor-specific, and servers should only + attempt to interpret it if they recognize the `extended-request' + name. + + The server may respond to such requests using any of the response + packets defined in Section ``Responses from the Server to the + Client''. Additionally, the server may also respond with a + SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does + not recognize the `extended-request' name, then the server MUST + respond with SSH_FXP_STATUS with error/status set to + SSH_FX_OP_UNSUPPORTED. + + The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary + extension-specific data from the server to the client. It is of the + following format: + + uint32 id + ... any request-specific data ... + + There is a range of packet types reserved for use by extensions. In + order to avoid collision, extensions that turn on the use of + additional packet types should determine those numbers dynamically. + + The suggested way of doing this is have an extension request from the + client to the server that enables the extension; the extension + response from the server to the client would specify the actual type + values to use, in additional to any other data. + + Extension authors should be mindful of the limited range of packet + types available (there are only 45 values available) and avoid + requiring a new packet type where possible. + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 28] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +9. Security Considerations + + This protocol assumes that it is run over a secure channel and that + the endpoints of the channel have been authenticated. Thus, this + protocol assumes that it is externally protected from network-level + attacks. + + This protocol provides file system access to arbitrary files on the + server (only constrained by the server implementation). It is the + responsibility of the server implementation to enforce any access + controls that may be required to limit the access allowed for any + particular user (the user being authenticated externally to this + protocol, typically using the SSH User Authentication Protocol [8]. + + Care must be taken in the server implementation to check the validity + of received file handle strings. The server should not rely on them + directly; it MUST check the validity of each handle before relying on + it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 29] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +10. Changes from previous protocol versions + + The SSH File Transfer Protocol has changed over time, before it's + standardization. The following is a description of the incompatible + changes between different versions. + +10.1 Changes between versions 4 and 3 + + Many of the changes between version 4 and version 3 are to the + attribute structure to make it more flexible for non-unix platforms. + + o Make all filenames UTF-8. + + o Added 'newline' extension. + + o Made file attribute owner and group strings so they can actually + be used on disparate systems. + + o Added createtime field, and added separate flags for atime, + createtime, and mtime so they can be set separately. + + o Split the file type out of the permissions field and into it's own + field (which is always present.) + + o Added acl attribute. + + o Added SSH_FXF_TEXT file open flag. + + o Added flags field to the get stat commands so that the client can + specifically request information the server might not normally + included for performance reasons. + + o Removed the long filename from the names structure-- it can now be + built from information available in the attrs structure. + + o Added reserved range of packet numbers for extensions. + + o Added several additional error codes. + + o Change the way version negotiate works slightly. Previously, if + the client version were higher than the server version, the server + was supposed to 'echo back' the clients version. The server now + sends it's own version and the lower of the two is considered to + be the one in use. + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 30] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +10.2 Changes between versions 3 and 2 + + o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. + + o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were + added. + + o The SSH_FXP_STATUS message was changed to include fields `error + message' and `language tag'. + + +10.3 Changes between versions 2 and 1 + + o The SSH_FXP_RENAME message was added. + + +10.4 Changes between versions 1 and 0 + + o Implementation changes, no actual protocol changes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 31] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +11. Trademark Issues + + "ssh" is a registered trademark of SSH Communications Security Corp + in the United States and/or other countries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 32] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +References + + [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and + P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January + 1999. + + [2] Alvestrand, H., "IETF Policy on Character Sets and Languages", + BCP 18, RFC 2277, January 1998. + + [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, + C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC + 3010, December 2000. + + [4] Institute of Electrical and Electronics Engineers, "Information + Technology - Portable Operating System Interface (POSIX) - Part + 1: System Application Program Interface (API) [C Language]", + IEEE Standard 1003.2, 1996. + + [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh- + architecture-13 (work in progress), September 2002. + + [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh- + transport-15 (work in progress), September 2002. + + [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16 + (work in progress), September 2002. + + [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh- + userauth-16 (work in progress), September 2002. + + +Authors' Addresses + + Joseph Galbraith + VanDyke Software + 4848 Tramway Ridge Blvd + Suite 101 + Albuquerque, NM 87111 + US + + Phone: +1 505 332 5700 + EMail: galb-list@vandyke.com + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 33] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: ylo@ssh.com + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 34] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 35] + + diff --git a/doc/draft-ietf-secsh-filexfer-04.txt b/doc/draft-ietf-secsh-filexfer-04.txt new file mode 100644 index 00000000..9f51883c --- /dev/null +++ b/doc/draft-ietf-secsh-filexfer-04.txt @@ -0,0 +1,2130 @@ + + + +Secure Shell Working Group J. Galbraith +Internet-Draft VanDyke Software +Expires: June 18, 2003 T. Ylonen + S. Lehtinen + SSH Communications Security Corp + December 18, 2002 + + + SSH File Transfer Protocol + draft-ietf-secsh-filexfer-04.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on June 18, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + The SSH File Transfer Protocol provides secure file transfer + functionality over any reliable data stream. It is the standard file + transfer protocol for use with the SSH2 protocol. This document + describes the file transfer protocol and its interface to the SSH2 + protocol suite. + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 1] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4 + 3. General Packet Format . . . . . . . . . . . . . . . . . . 5 + 3.1 The use of stderr in the server . . . . . . . . . . . . . 6 + 4. Protocol Initialization . . . . . . . . . . . . . . . . . 8 + 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 8 + 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 8 + 4.3 Determining Server Newline Convention . . . . . . . . . . 9 + 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 10 + 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 11 + 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 12 + 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 14 + 6. Requests From the Client to the Server . . . . . . . . . . 15 + 6.1 Request Synchronization and Reordering . . . . . . . . . . 15 + 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 16 + 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 16 + 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 19 + 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 20 + 6.6 Creating and Deleting Directories . . . . . . . . . . . . 21 + 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 21 + 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 22 + 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 23 + 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 24 + 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 25 + 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 25 + 7. Responses from the Server to the Client . . . . . . . . . 26 + 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 30 + 9. Security Considerations . . . . . . . . . . . . . . . . . 31 + 10. Changes from previous protocol versions . . . . . . . . . 32 + 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 32 + 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 33 + 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 33 + 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 33 + 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 34 + References . . . . . . . . . . . . . . . . . . . . . . . . 35 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . 35 + Intellectual Property and Copyright Statements . . . . . . 37 + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 2] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +1. Introduction + + This protocol provides secure file transfer (and more generally file + system access) functionality over a reliable data stream, such as a + channel in the SSH2 protocol [5]. + + This protocol is designed so that it could be used to implement a + secure remote file system service, as well as a secure file transfer + service. + + This protocol assumes that it runs over a secure channel, and that + the server has already authenticated the user at the client end, and + that the identity of the client user is externally available to the + server implementation. + + In general, this protocol follows a simple request-response model. + Each request and response contains a sequence number and multiple + requests may be pending simultaneously. There are a relatively large + number of different request messages, but a small number of possible + response messages. Each request has one or more response messages + that may be returned in result (e.g., a read either returns data or + reports error status). + + The packet format descriptions in this specification follow the + notation presented in the secsh architecture draft. [5] + + Even though this protocol is described in the context of the SSH2 + protocol, this protocol is general and independent of the rest of the + SSH2 protocol suite. It could be used in a number of different + applications, such as secure file transfer over TLS RFC 2246 [1] and + transfer of management information in VPN applications. + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 3] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +2. Use with the SSH Connection Protocol + + When used with the SSH2 Protocol suite, this protocol is intended to + be used from the SSH Connection Protocol [7] as a subsystem, as + described in section ``Starting a Shell or a Command''. The + subsystem name used with this protocol is "sftp". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 4] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +3. General Packet Format + + All packets transmitted over the secure connection are of the + following format: + + uint32 length + byte type + byte[length - 1] data payload + + That is, they are just data preceded by 32-bit length and 8-bit type + fields. The `length' is the length of the data area, and does not + include the `length' field itself. The format and interpretation of + the data area depends on the packet type. + + All packet descriptions below only specify the packet type and the + data that goes into the data field. Thus, they should be prefixed by + the `length' and `type' fields. + + The maximum size of a packet is in practice determined by the client + (the maximum size of read or write requests that it sends, plus a few + bytes of packet overhead). All servers SHOULD support packets of at + least 34000 bytes (where the packet size refers to the full length, + including the header above). This should allow for reads and writes + of at most 32768 bytes. + + There is no limit on the number of outstanding (non-acknowledged) + requests that the client may send to the server. In practice this is + limited by the buffering available on the data stream and the queuing + performed by the server. If the server's queues are full, it should + not read any more data from the stream, and flow control will prevent + the client from sending more requests. Note, however, that while + there is no restriction on the protocol level, the client's API may + provide a limit in order to prevent infinite queuing of outgoing + requests at the client. + + The following values are defined for packet types. + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 5] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + #define SSH_FXP_INIT 1 + #define SSH_FXP_VERSION 2 + #define SSH_FXP_OPEN 3 + #define SSH_FXP_CLOSE 4 + #define SSH_FXP_READ 5 + #define SSH_FXP_WRITE 6 + #define SSH_FXP_LSTAT 7 + #define SSH_FXP_FSTAT 8 + #define SSH_FXP_SETSTAT 9 + #define SSH_FXP_FSETSTAT 10 + #define SSH_FXP_OPENDIR 11 + #define SSH_FXP_READDIR 12 + #define SSH_FXP_REMOVE 13 + #define SSH_FXP_MKDIR 14 + #define SSH_FXP_RMDIR 15 + #define SSH_FXP_REALPATH 16 + #define SSH_FXP_STAT 17 + #define SSH_FXP_RENAME 18 + #define SSH_FXP_READLINK 19 + #define SSH_FXP_SYMLINK 20 + + #define SSH_FXP_STATUS 101 + #define SSH_FXP_HANDLE 102 + #define SSH_FXP_DATA 103 + #define SSH_FXP_NAME 104 + #define SSH_FXP_ATTRS 105 + + #define SSH_FXP_EXTENDED 200 + #define SSH_FXP_EXTENDED_REPLY 201 + + RESERVED_FOR_EXTENSIONS 210-255 + + Additional packet types should only be defined if the protocol + version number (see Section ``Protocol Initialization'') is + incremented, and their use MUST be negotiated using the version + number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY + packets can be used to implement vendor-specific extensions. See + Section ``Vendor-Specific-Extensions'' for more details. + +3.1 The use of stderr in the server + + Packets are sent and received on stdout and stdin. Data sent on + stderr by the server SHOULD be considered debug or supplemental error + information, and MAY be displayed to the user. + + For example, during initialization, there is no client request + active, so errors or warning information cannot be sent to the client + as part of the SFTP protocol at this early stage. However, the + + + +Galbraith, et al. Expires June 18, 2003 [Page 6] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + errors or warnings MAY be sent as stderr text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 7] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +4. Protocol Initialization + + When the file transfer protocol starts, the client first sends a + SSH_FXP_INIT (including its version number) packet to the server. + The server responds with a SSH_FXP_VERSION packet, supplying the + lowest of its own and the client's version number. Both parties + should from then on adhere to particular version of the protocol. + + The version number of the protocol specified in this document is 4. + The version number should be incremented for each incompatible + revision of this protocol. + +4.1 Client Initialization + + The SSH_FXP_INIT packet (from client to server) has the following + data: + + uint32 version + + Version 3 of this protocol allowed clients to include extensions in + the SSH_FXP_INIT packet; however, this can cause interoperability + problems with version 1 and version 2 servers because the client must + send this packet before knowing the servers version. + + In this version of the protocol, clients MUST use the + SSH_FXP_EXTENDED packet to send extensions to the server after + version exchange has completed. Clients MUST NOT include extensions + in the version packet. This will prevent interoperability problems + with older servers + +4.2 Server Initialization + + The SSH_FXP_VERSION packet (from server to client) has the following + data: + + uint32 version + + + 'version' is the lower of the protocol version supported by the + server and the version number received from the client. + + The extension data may be empty, or may be a sequence of + + string extension_name + string extension_data + + pairs (both strings MUST always be present if one is, but the + `extension_data' string may be of zero length). If present, these + + + +Galbraith, et al. Expires June 18, 2003 [Page 8] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + strings indicate extensions to the baseline protocol. The + `extension_name' field(s) identify the name of the extension. The + name should be of the form "name@domain", where the domain is the DNS + domain name of the organization defining the extension. Additional + names that are not of this format may be defined later by the IETF. + Implementations MUST silently ignore any extensions whose name they + do not recognize. + +4.3 Determining Server Newline Convention + + In order to correctly process text files in a cross platform + compatible way, the newline convention must be converted from that of + the server to that of the client, or, during an upload, from that of + the client to that of the server. + + Versions 3 and prior of this protocol made no provisions for + processing text files. Many clients implemented some sort of + conversion algorithm, but without either a 'canonical' on the wire + format or knowledge of the servers newline convention, correct + conversion was not always possible. + + Starting with Version 4, the SSH_FXF_TEXT file open flag (Section + 6.3) makes it possible to request that the server translate a file to + a 'canonical' on the wire format. This format uses \r\n as the line + separator. + + Servers for systems using multiple newline characters (for example, + Mac OS X or VMS) or systems using counted records, MUST translate to + the canonical form. + + However, to ease the burden of implementation on servers that use a + single, simple separator sequence, the following extension allows the + canonical format to be changed. + + string "newline" + string new-canonical-separator (usually "\r" or "\n" or "\r\n") + + All clients MUST support this extension. + + When processing text files, clients SHOULD NOT translate any + character or sequence that is not an exact match of the servers + newline separator. + + In particular, if the newline sequence being used is the canonical + "\r\n" sequence, a lone \r or a lone \n SHOULD be written through + without change. + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 9] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +5. File Attributes + + A new compound data type is defined for encoding file attributes. + The same encoding is used both when returning file attributes from + the server and when sending file attributes to the server. When + sending it to the server, the flags field specifies which attributes + are included, and the server will use default values for the + remaining attributes (or will not modify the values of remaining + attributes). When receiving attributes from the server, the flags + specify which attributes are included in the returned data. The + server normally returns all attributes it knows about. + + uint32 flags + byte type always present + uint64 size present only if flag SIZE + string owner present only if flag OWNERGROUP + string group present only if flag OWNERGROUP + uint32 permissions present only if flag PERMISSIONS + uint64 atime present only if flag ACCESSTIME + uint32 atime_nseconds present only if flag SUBSECOND_TIMES + uint64 createtime present only if flag CREATETIME + uint32 createtime_nseconds present only if flag SUBSECOND_TIMES + uint64 mtime present only if flag MODIFYTIME + uint32 mtime_nseconds present only if flag SUBSECOND_TIMES + string acl present only if flag ACL + uint32 extended_count present only if flag EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count + + +5.1 Flags + + The `flags' specify which of the fields are present. Those fields + for which the corresponding flag is not set are not present (not + included in the packet). New flags can only be added by incrementing + the protocol version number (or by using the extension mechanism + described below). + + The flags bits are defined to have the following values: + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 10] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + #define SSH_FILEXFER_ATTR_SIZE 0x00000001 + #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000040 + #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 + #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 + #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 + #define SSH_FILEXFER_ATTR_ACL 0x00000040 + #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 + #define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100 + #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 + + In previous versions of this protocol flags value 0x00000002 was + SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP + was given a new value in order to ease implementation burden. + 0x00000002 MUST NOT appear in the mask. Some future version of this + protocol may reuse flag 0x00000002. + +5.2 Type + + The type field is always present. The following types are defined: + + #define SSH_FILEXFER_TYPE_REGULAR 1 + #define SSH_FILEXFER_TYPE_DIRECTORY 2 + #define SSH_FILEXFER_TYPE_SYMLINK 3 + #define SSH_FILEXFER_TYPE_SPECIAL 4 + #define SSH_FILEXFER_TYPE_UNKNOWN 5 + + On a POSIX system, these values would be derived from the permission + field. + +5.3 Size + + The `size' field specifies the size of the file on disk, in bytes. + If it is present during file creation, it should be considered a hint + as to the files eventual size. + + Files opened with the SSH_FXF_TEXT flag may have a size that is + greater or less than the value of the size field. + +5.4 Owner and Group + + The `owner' and `group' fields are represented as UTF-8 strings; this + is the form used by NFS v4. See NFS version 4 Protocol. [3] The + following text is selected quotations from section 5.6. + + To avoid a representation that is tied to a particular underlying + implementation at the client or server, the use of UTF-8 strings has + been chosen. The string should be of the form user@dns_domain". + This will allow for a client and server that do not use the same + + + +Galbraith, et al. Expires June 18, 2003 [Page 11] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + local representation the ability to translate to a common syntax that + can be interpreted by both. In the case where there is no + translation available to the client or server, the attribute value + must be constructed without the "@". Therefore, the absence of the @ + from the owner or owner_group attribute signifies that no translation + was available and the receiver of the attribute should not place any + special meaning with the attribute value. Even though the attribute + value can not be translated, it may still be useful. In the case of + a client, the attribute string may be used for local display of + ownership. + +5.5 Permissions + + The `permissions' field contains a bit mask of file permissions as + defined by POSIX [1]. + +5.6 Times + + The 'atime', 'createtime', and 'mtime' contain the access, creation, + and modification times of the files, respectively. They are + represented as seconds from Jan 1, 1970 in UTC. + + A negative value indicates number of seconds before Jan 1, 1970. In + both cases, if the SSH_FILEXFER_ATTR_SUBSECOND_TIMES flag is set, the + nseconds field is to be added to the seconds field for the final time + representation. For example, if the time to be represented is + one-half second before 0 hour January 1, 1970, the seconds field + would have a value of negative one (-1) and the nseconds fields would + have a value of one-half second (500000000). Values greater than + 999,999,999 for nseconds are considered invalid. + +5.7 ACL + + The 'ACL' field contains an ACL similar to that defined in section + 5.9 of NFS version 4 Protocol [3]. + + uint32 ace-count + + repeated ace-count time: + uint32 ace-type + uint32 ace-flag + uint32 ace-mask + string who [UTF-8] + + ace-type is one of the following four values (taken from NFS Version + 4 Protocol [3]: + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 12] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000; + const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001; + const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002; + const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003; + + ace-flag is a combination of the following flag values. See NFS + Version 4 Protocol [3] section 5.9.2: + + const ACE4_FILE_INHERIT_ACE = 0x00000001; + const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002; + const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004; + const ACE4_INHERIT_ONLY_ACE = 0x00000008; + const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010; + const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020; + const ACE4_IDENTIFIER_GROUP = 0x00000040; + + ace-mask is any combination of the following flags (taken from NFS + Version 4 Protocol [3] section 5.9.3: + + const ACE4_READ_DATA = 0x00000001; + const ACE4_LIST_DIRECTORY = 0x00000001; + const ACE4_WRITE_DATA = 0x00000002; + const ACE4_ADD_FILE = 0x00000002; + const ACE4_APPEND_DATA = 0x00000004; + const ACE4_ADD_SUBDIRECTORY = 0x00000004; + const ACE4_READ_NAMED_ATTRS = 0x00000008; + const ACE4_WRITE_NAMED_ATTRS = 0x00000010; + const ACE4_EXECUTE = 0x00000020; + const ACE4_DELETE_CHILD = 0x00000040; + const ACE4_READ_ATTRIBUTES = 0x00000080; + const ACE4_WRITE_ATTRIBUTES = 0x00000100; + const ACE4_DELETE = 0x00010000; + const ACE4_READ_ACL = 0x00020000; + const ACE4_WRITE_ACL = 0x00040000; + const ACE4_WRITE_OWNER = 0x00080000; + const ACE4_SYNCHRONIZE = 0x00100000; + + who is a UTF-8 string of the form described in 'Owner and Group' + (Section 5.4) + + Also, as per '5.9.4 ACE who' [3] there are several identifiers that + need to be understood universally. Some of these identifiers cannot + be understood when an client access the server, but have meaning when + a local process accesses the file. The ability to display and modify + these permissions is permitted over SFTP. + + OWNER The owner of the file. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 13] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + GROUP The group associated with the file. + + EVERYONE The world. + + INTERACTIVE Accessed from an interactive terminal. + + NETWORK Accessed via the network. + + DIALUP Accessed as a dialup user to the server. + + BATCH Accessed from a batch job. + + ANONYMOUS Accessed without any authentication. + + AUTHENTICATED Any authenticated user (opposite of ANONYMOUS). + + SERVICE Access from a system service. + + To avoid conflict, these special identifiers are distinguish by an + appended "@" and should appear in the form "xxxx@" (note: no domain + name after the "@"). For example: ANONYMOUS@. + +5.8 Extended attributes + + The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension + mechanism for vendor-specific extensions. If the flag is specified, + then the `extended_count' field is present. It specifies the number + of extended_type-extended_data pairs that follow. Each of these + pairs specifies an extended attribute. For each of the attributes, + the extended_type field should be a string of the format + "name@domain", where "domain" is a valid, registered domain name and + "name" identifies the method. The IETF may later standardize certain + names that deviate from this format (e.g., that do not contain the + "@" sign). The interpretation of `extended_data' depends on the + type. Implementations SHOULD ignore extended data fields that they + do not understand. + + Additional fields can be added to the attributes by either defining + additional bits to the flags field to indicate their presence, or by + defining extended attributes for them. The extended attributes + mechanism is recommended for most purposes; additional flags bits + should only be defined by an IETF standards action that also + increments the protocol version number. The use of such new fields + MUST be negotiated by the version number in the protocol exchange. + It is a protocol error if a packet with unsupported protocol bits is + received. + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 14] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +6. Requests From the Client to the Server + + Requests from the client to the server represent the various file + system operations. Each request begins with an `id' field, which is + a 32-bit identifier identifying the request (selected by the client). + The same identifier will be returned in the response to the request. + One possible implementation is a monotonically increasing request + sequence number (modulo 2^32). + + Many operations in the protocol operate on open files. The + SSH_FXP_OPEN request can return a file handle (which is an opaque + variable-length string) which may be used to access the file later + (e.g. in a read operation). The client MUST NOT send requests the + server with bogus or closed handles. However, the server MUST + perform adequate checks on the handle in order to avoid security + risks due to fabricated handles. + + This design allows either stateful and stateless server + implementation, as well as an implementation which caches state + between requests but may also flush it. The contents of the file + handle string are entirely up to the server and its design. The + client should not modify or attempt to interpret the file handle + strings. + + The file handle strings MUST NOT be longer than 256 bytes. + +6.1 Request Synchronization and Reordering + + The protocol and implementations MUST process requests relating to + the same file in the order in which they are received. In other + words, if an application submits multiple requests to the server, the + results in the responses will be the same as if it had sent the + requests one at a time and waited for the response in each case. For + example, the server may process non-overlapping read/write requests + to the same file in parallel, but overlapping reads and writes cannot + be reordered or parallelized. However, there are no ordering + restrictions on the server for processing requests from two different + file transfer connections. The server may interleave and parallelize + them at will. + + There are no restrictions on the order in which responses to + outstanding requests are delivered to the client, except that the + server must ensure fairness in the sense that processing of no + request will be indefinitely delayed even if the client is sending + other requests so that there are multiple outstanding requests all + the time. + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 15] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +6.2 File Names + + This protocol represents file names as strings. File names are + assumed to use the slash ('/') character as a directory separator. + + File names starting with a slash are "absolute", and are relative to + the root of the file system. Names starting with any other character + are relative to the user's default directory (home directory). Note + that identifying the user is assumed to take place outside of this + protocol. + + Servers SHOULD interpret a path name component ".." as referring to + the parent directory, and "." as referring to the current directory. + If the server implementation limits access to certain parts of the + file system, it must be extra careful in parsing file names when + enforcing such restrictions. There have been numerous reported + security bugs where a ".." in a path name has allowed access outside + the intended area. + + An empty path name is valid, and it refers to the user's default + directory (usually the user's home directory). + + Otherwise, no syntax is defined for file names by this specification. + Clients should not make any other assumptions; however, they can + splice path name components returned by SSH_FXP_READDIR together + using a slash ('/') as the separator, and that will work as expected. + + In order to comply with IETF Policy on Character Sets and Languages + [2], all filenames are to be encoded in UTF-8. The shortest valid + UTF-8 encoding of the UNICODE data MUST be used. The server is + responsible for converting the UNICODE data to whatever canonical + form it requires. + + For example, if the server requires that precomposed characters + always be used, the server MUST NOT assume the filename as sent by + the client has this attribute, but must do this normalization itself. + + It is understood that the lack of well-defined semantics for file + names may cause interoperability problems between clients and servers + using radically different operating systems. However, this approach + is known to work acceptably with most systems, and alternative + approaches that e.g. treat file names as sequences of structured + components are quite complicated. + +6.3 Opening, Creating, and Closing Files + + Files are opened and created using the SSH_FXP_OPEN message, whose + data part is as follows: + + + +Galbraith, et al. Expires June 18, 2003 [Page 16] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + uint32 id + string filename [UTF-8] + uint32 pflags + ATTRS attrs + + The `id' field is the request identifier as for all requests. + + The `filename' field specifies the file name. See Section ``File + Names'' for more information. + + The `pflags' field is a bitmask. The following bits have been + defined. + + #define SSH_FXF_READ 0x00000001 + #define SSH_FXF_WRITE 0x00000002 + #define SSH_FXF_APPEND 0x00000004 + #define SSH_FXF_CREAT 0x00000008 + #define SSH_FXF_TRUNC 0x00000010 + #define SSH_FXF_EXCL 0x00000020 + #define SSH_FXF_TEXT 0x00000040 + + These have the following meanings: + + SSH_FXF_READ + Open the file for reading. + + SSH_FXF_WRITE + Open the file for writing. If both this and SSH_FXF_READ are + specified, the file is opened for both reading and writing. + + SSH_FXF_APPEND + Force all writes to append data at the end of the file. The + offset parameter to write will be ignored. + + SSH_FXF_CREAT + If this flag is specified, then a new file will be created if one + does not already exist (if O_TRUNC is specified, the new file will + be truncated to zero length if it previously exists). + + SSH_FXF_TRUNC + Forces an existing file with the same name to be truncated to zero + length when creating a file by specifying SSH_FXF_CREAT. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + SSH_FXF_EXCL + Causes the request to fail if the named file already exists. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 17] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + SSH_FXF_TEXT + Indicates that the server should treat the file as text and + convert it to the canonical newline convention in use. (See + Determining Server Newline Convention. (Section 4.3) + + When a file is opened with the FXF_TEXT flag, the offset field in + both the read and write function are ignored. + + Servers MUST correctly process multiple parallel reads and writes + correctly in this mode. Naturally, it is permissible for them to + do this by serializing the requests. It would not be possible for + a client to reliably detect a server that does not implement + parallel writes in time to prevent damage. + + Clients SHOULD use the SSH_FXF_APPEND flag to append data to a + text file rather then using write with a calculated offset. + + To support seeks on text file the following SSH_FXP_EXTENDED + packet is defined. + + + + string "text-seek" + string file-handle + uint64 line-number + + line-number is the index of the line number to seek to, where byte + 0 in the file is line number 0, and the byte directly following + the first newline sequence in the file is line number 1 and so on. + + The response to a "text-seek" request is an SSH_FXP_STATUS + message. + + An attempt to seek past the end-of-file should result in a + SSH_FX_EOF status. + + Servers SHOULD support at least one "text-seek" in order to + support resume. However, a client MUST be prepared to receive + SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation. + The client can then try a fall-back strategy, if it has one. + + Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned + for read or write operations that are not sequential. + + The `attrs' field specifies the initial attributes for the file. + Default values will be used for those attributes that are not + specified. See Section ``File Attributes'' for more information. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 18] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + The response to this message will be either SSH_FXP_HANDLE (if the + operation is successful) or SSH_FXP_STATUS (if the operation fails). + + A file is closed by using the SSH_FXP_CLOSE request. Its data field + has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + previously returned in the response to SSH_FXP_OPEN or + SSH_FXP_OPENDIR. The handle becomes invalid immediately after this + request has been sent. + + The response to this request will be a SSH_FXP_STATUS message. One + should note that on some server platforms even a close can fail. + This can happen e.g. if the server operating system caches writes, + and an error occurs while flushing cached writes during the close. + +6.4 Reading and Writing + + Once a file has been opened, it can be read using the following + message: + + byte SSH_FXP_READ + uint32 id + string handle + uint64 offset + uint32 len + + where `id' is the request identifier, `handle' is an open file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative + to the beginning of the file from where to start reading, and `len' + is the maximum number of bytes to read. + + In response to this request, the server will read as many bytes as it + can from the file (up to `len'), and return them in a SSH_FXP_DATA + message. If an error occurs or EOF is encountered before reading any + data, the server will respond with SSH_FXP_STATUS. + + For normal disk files, it is normally guaranteed that this will read + the specified number of bytes, or up to end of file. However, if the + read length is very long, the server may truncate it if it doesn't + support packets of that length. See General Packet Format (Section + 3). + + For e.g. device files this may return fewer bytes than requested. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 19] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + Writing to a file is achieved using the following message: + + byte SSH_FXP_WRITE + uint32 id + string handle + uint64 offset + string data + + where `id' is a request identifier, `handle' is a file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the + beginning of the file where to start writing, and `data' is the data + to be written. + + The write will extend the file if writing beyond the end of the file. + It is legal to write way beyond the end of the file; the semantics + are to write zeroes from the end of the file to the specified offset + and then the data. On most operating systems, such writes do not + allocate disk space but instead leave "holes" in the file. + + The server responds to a write request with a SSH_FXP_STATUS message. + +6.5 Removing and Renaming Files + + Files can be removed using the SSH_FXP_REMOVE message. It has the + following format: + + uint32 id + string filename [UTF-8] + + where `id' is the request identifier and `filename' is the name of + the file to be removed. See Section ``File Names'' for more + information. This request cannot be used to remove directories. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + Files (and directories) can be renamed using the SSH_FXP_RENAME + message. Its data is as follows: + + uint32 id + string oldpath [UTF-8] + string newpath [UTF-8] + + where `id' is the request identifier, `oldpath' is the name of an + existing file or directory, and `newpath' is the new name for the + file or directory. It is an error if there already exists a file + with the name specified by newpath. The server may also fail rename + requests in other situations, for example if `oldpath' and `newpath' + + + +Galbraith, et al. Expires June 18, 2003 [Page 20] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + point to different file systems on the server. + + The server will respond to this request with a SSH_FXP_STATUS + message. + +6.6 Creating and Deleting Directories + + New directories can be created using the SSH_FXP_MKDIR request. It + has the following format: + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier. + + `path' specifies the directory to be created. See Section ``File + Names'' for more information on file names. + + `attrs' specifies the attributes that should be applied to it upon + creation. Attributes are discussed in more detail in Section ``File + Attributes''. + + The server will respond to this request with a SSH_FXP_STATUS + message. If a file or directory with the specified path already + exists, an error will be returned. + + Directories can be removed using the SSH_FXP_RMDIR request, which has + the following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier, and `path' specifies the + directory to be removed. See Section ``File Names'' for more + information on file names. + + The server responds to this request with a SSH_FXP_STATUS message. + Errors may be returned from this operation for various reasons, + including, but not limited to, the path does not exist, the path does + not refer to a directory object, the directory is not empty, or the + user has insufficient access or permission to perform the requested + operation. + +6.7 Scanning Directories + + The files in a directory can be listed using the SSH_FXP_OPENDIR and + SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one + + + +Galbraith, et al. Expires June 18, 2003 [Page 21] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + or more file names with full file attributes for each file. The + client should call SSH_FXP_READDIR repeatedly until it has found the + file it is looking for or until the server responds with a + SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if + there are no more files in the directory). The client should then + close the handle using the SSH_FXP_CLOSE request. + + The SSH_FXP_OPENDIR opens a directory for reading. It has the + following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' is the path name of + the directory to be listed (without any trailing slash). See Section + ``File Names'' for more information on file names. This will return + an error if the path does not specify a directory or if the directory + is not readable. The server will respond to this request with either + a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. + + Once the directory has been successfully opened, files (and + directories) contained in it can be listed using SSH_FXP_READDIR + requests. These are of the format + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to + use an ordinary file handle returned by SSH_FXP_OPEN.) + + The server responds to this request with either a SSH_FXP_NAME or a + SSH_FXP_STATUS message. One or more names may be returned at a time. + Full status information is returned for each name in order to speed + up typical directory listings. + + If there are no more names available to be read, the server MUST + respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF. + + When the client no longer wishes to read more names from the + directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle + should be closed regardless of whether an error has occurred or not. + +6.8 Retrieving File Attributes + + Very often, file attributes are automatically returned by + SSH_FXP_READDIR. However, sometimes there is need to specifically + retrieve the attributes for a named file. This can be done using the + + + +Galbraith, et al. Expires June 18, 2003 [Page 22] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. + + SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT + follows symbolic links on the server, whereas SSH_FXP_LSTAT does not + follow symbolic links. Both have the same format: + + uint32 id + string path [UTF-8] + uint32 flags + + where `id' is the request identifier, and `path' specifies the file + system object for which status is to be returned. The server + responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. + + The flags field specify the attribute flags in which the client has + particular interest. This is a hint to the server. For example, + because retrieving owner / group and acl information can be an + expensive operation under some operating systems, the server may + choose not to retrieve this information unless the client expresses a + specific interest in it. + + The client has no guarantee the server will provide all the fields + that it has expressed an interest in. + + SSH_FXP_FSTAT differs from the others in that it returns status + information for an open file (identified by the file handle). Its + format is as follows: + + uint32 id + string handle + uint32 flags + + where `id' is the request identifier and `handle' is a file handle + returned by SSH_FXP_OPEN. The server responds to this request with + SSH_FXP_ATTRS or SSH_FXP_STATUS. + +6.9 Setting File Attributes + + File attributes may be modified using the SSH_FXP_SETSTAT and + SSH_FXP_FSETSTAT requests. These requests are used for operations + such as changing the ownership, permissions or access times, as well + as for truncating a file. + + The SSH_FXP_SETSTAT request is of the following format: + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 23] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `path' specifies the file + system object (e.g. file or directory) whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. + + An error will be returned if the specified file system object does + not exist or the user does not have sufficient rights to modify the + specified attributes. The server responds to this request with a + SSH_FXP_STATUS message. + + The SSH_FXP_FSETSTAT request modifies the attributes of a file which + is already open. It has the following format: + + uint32 id + string handle + ATTRS attrs + + where `id' is the request identifier, `handle' (MUST be returned by + SSH_FXP_OPEN) identifies the file whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. The server will respond to this request with + SSH_FXP_STATUS. + +6.10 Dealing with Symbolic links + + The SSH_FXP_READLINK request may be used to read the target of a + symbolic link. It would have a data part as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name of the symlink to be read. + + The server will respond with a SSH_FXP_NAME packet containing only + one name and a dummy attributes value. The name in the returned + packet contains the target of the link. If an error occurs, the + server may respond with SSH_FXP_STATUS. + + The SSH_FXP_SYMLINK request will create a symbolic link on the + server. It is of the following format + + + + +Galbraith, et al. Expires June 18, 2003 [Page 24] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + uint32 id + string linkpath [UTF-8] + string targetpath [UTF-8] + + where `id' is the request identifier, `linkpath' specifies the path + name of the symlink to be created and `targetpath' specifies the + target of the symlink. The server shall respond with a + SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error + condition. + +6.11 Canonicalizing the Server-Side Path Name + + The SSH_FXP_REALPATH request can be used to have the server + canonicalize any given path name to an absolute path. This is useful + for converting path names containing ".." components or relative + pathnames without a leading slash into absolute paths. The format of + the request is as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name to be canonicalized. The server will respond with a + SSH_FXP_NAME packet containing the name in canonical form and a dummy + attributes value. If an error occurs, the server may also respond + with SSH_FXP_STATUS. + +6.11.1 Best practice for dealing with paths + + The client SHOULD treat the results of SSH_FXP_REALPATH as a + canonical absolute path, even if the path does not appear to be + absolute. A client that use REALPATH(".") and treats the result as + absolute, even if there is no leading slash, will continue to + function correctly, even when talking to a Windows NT or VMS style + system, where absolute paths may not begin with a slash. + + For example, if the client wishes to change directory up, and the + server has returned "c:/x/y/z" from REALPATH, the client SHOULD use + "c:/x/y/z/..". + + As a second example, if the client wishes to open the file "x.txt" in + the current directory, and server has returned "dka100:/x/y/z" as the + canonical path of the directory, the client SHOULD open "dka100:/x/y/ + z/x.txt" + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 25] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +7. Responses from the Server to the Client + + The server responds to the client using one of a few response + packets. All requests can return a SSH_FXP_STATUS response upon + failure. When the operation is successful, any of the responses may + be returned (depending on the operation). If no data needs to be + returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK + status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used + to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR + requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, + SSH_FXP_NAME is used to return one or more file names from a + SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is + used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and + SSH_FXP_FSTAT requests. + + Exactly one response will be returned for each request. Each + response packet contains a request identifier which can be used to + match each response with the corresponding request. Note that it is + legal to have several requests outstanding simultaneously, and the + server is allowed to send responses to them in a different order from + the order in which the requests were sent (the result of their + execution, however, is guaranteed to be as if they had been processed + one at a time in the order in which the requests were sent). + + Response packets are of the same general format as request packets. + Each response packet begins with the request identifier. + + The format of the data portion of the SSH_FXP_STATUS response is as + follows: + + uint32 id + uint32 error/status code + string error message (ISO-10646 UTF-8 [RFC-2279]) + string language tag (as defined in [RFC-1766]) + + where `id' is the request identifier, and `error/status code' + indicates the result of the requested operation. The value SSH_FX_OK + indicates success, and all other values indicate failure. + + Currently, the following values are defined (other values may be + defined by future versions of this protocol): + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 26] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + #define SSH_FX_OK 0 + #define SSH_FX_EOF 1 + #define SSH_FX_NO_SUCH_FILE 2 + #define SSH_FX_PERMISSION_DENIED 3 + #define SSH_FX_FAILURE 4 + #define SSH_FX_BAD_MESSAGE 5 + #define SSH_FX_NO_CONNECTION 6 + #define SSH_FX_CONNECTION_LOST 7 + #define SSH_FX_OP_UNSUPPORTED 8 + #define SSH_FX_INVALID_HANDLE 9 + #define SSH_FX_NO_SUCH_PATH 10 + #define SSH_FX_FILE_ALREADY_EXISTS 11 + #define SSH_FX_WRITE_PROTECT 12 + #define SSH_FX_NO_MEDIA 13 + + SSH_FX_OK + Indicates successful completion of the operation. + + SSH_FX_EOF + indicates end-of-file condition; for SSH_FX_READ it means that no + more data is available in the file, and for SSH_FX_READDIR it + indicates that no more files are contained in the directory. + + SSH_FX_NO_SUCH_FILE + is returned when a reference is made to a file which does not + exist. + + SSH_FX_PERMISSION_DENIED + is returned when the authenticated user does not have sufficient + permissions to perform the operation. + + SSH_FX_FAILURE + is a generic catch-all error message; it should be returned if an + error occurs for which there is no more specific error code + defined. + + SSH_FX_BAD_MESSAGE + may be returned if a badly formatted packet or protocol + incompatibility is detected. + + SSH_FX_NO_CONNECTION + is a pseudo-error which indicates that the client has no + connection to the server (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + SSH_FX_CONNECTION_LOST + is a pseudo-error which indicates that the connection to the + server has been lost (it can only be generated locally by the + + + +Galbraith, et al. Expires June 18, 2003 [Page 27] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + client, and MUST NOT be returned by servers). + + SSH_FX_OP_UNSUPPORTED + indicates that an attempt was made to perform an operation which + is not supported for the server (it may be generated locally by + the client if e.g. the version number exchange indicates that a + required feature is not supported by the server, or it may be + returned by the server if the server does not implement an + operation). + + SSH_FX_INVALID_HANDLE + The handle value was invalid. + + SSH_FX_NO_SUCH_PATH + The file path does not exist or is invalid. + + SSH_FX_FILE_ALREADY_EXISTS + The file already exists. + + SSH_FX_WRITE_PROTECT + The file is on read only media, or the media is write protected. + + SSH_FX_NO_MEDIA + The requested operation can not be completed because there is no + media available in the drive. + + The SSH_FXP_HANDLE response has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is an arbitrary + string that identifies an open file or directory on the server. The + handle is opaque to the client; the client MUST NOT attempt to + interpret or modify it in any way. The length of the handle string + MUST NOT exceed 256 data bytes. + + The SSH_FXP_DATA response has the following format: + + uint32 id + string data + + where `id' is the request identifier, and `data' is an arbitrary byte + string containing the requested data. The data string may be at most + the number of bytes requested in a SSH_FXP_READ request, but may also + be shorter if end of file is reached or if the read is from something + other than a regular file. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 28] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + The SSH_FXP_NAME response has the following format: + + uint32 id + uint32 count + repeats count times: + string filename [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `count' is the number of names + returned in this response, and the remaining fields repeat `count' + times (so that all three fields are first included for the first + file, then for the second file, etc). In the repeated part, + `filename' is a file name being returned (for SSH_FXP_READDIR, it + will be a relative name within the directory, without any path + components; for SSH_FXP_REALPATH it will be an absolute path name), + and `attrs' is the attributes of the file as described in Section + ``File Attributes''. + + The SSH_FXP_ATTRS response has the following format: + + uint32 id + ATTRS attrs + + where `id' is the request identifier, and `attrs' is the returned + file attributes as described in Section ``File Attributes''. + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 29] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +8. Vendor-Specific Extensions + + The SSH_FXP_EXTENDED request provides a generic extension mechanism + for adding vendor-specific commands. The request has the following + format: + + uint32 id + string extended-request + ... any request-specific data ... + + where `id' is the request identifier, and `extended-request' is a + string of the format "name@domain", where domain is an internet + domain name of the vendor defining the request. The rest of the + request is completely vendor-specific, and servers should only + attempt to interpret it if they recognize the `extended-request' + name. + + The server may respond to such requests using any of the response + packets defined in Section ``Responses from the Server to the + Client''. Additionally, the server may also respond with a + SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does + not recognize the `extended-request' name, then the server MUST + respond with SSH_FXP_STATUS with error/status set to + SSH_FX_OP_UNSUPPORTED. + + The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary + extension-specific data from the server to the client. It is of the + following format: + + uint32 id + ... any request-specific data ... + + There is a range of packet types reserved for use by extensions. In + order to avoid collision, extensions that turn on the use of + additional packet types should determine those numbers dynamically. + + The suggested way of doing this is have an extension request from the + client to the server that enables the extension; the extension + response from the server to the client would specify the actual type + values to use, in additional to any other data. + + Extension authors should be mindful of the limited range of packet + types available (there are only 45 values available) and avoid + requiring a new packet type where possible. + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 30] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +9. Security Considerations + + This protocol assumes that it is run over a secure channel and that + the endpoints of the channel have been authenticated. Thus, this + protocol assumes that it is externally protected from network-level + attacks. + + This protocol provides file system access to arbitrary files on the + server (only constrained by the server implementation). It is the + responsibility of the server implementation to enforce any access + controls that may be required to limit the access allowed for any + particular user (the user being authenticated externally to this + protocol, typically using the SSH User Authentication Protocol [8]. + + Care must be taken in the server implementation to check the validity + of received file handle strings. The server should not rely on them + directly; it MUST check the validity of each handle before relying on + it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 31] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +10. Changes from previous protocol versions + + The SSH File Transfer Protocol has changed over time, before it's + standardization. The following is a description of the incompatible + changes between different versions. + +10.1 Changes between versions 4 and 3 + + Many of the changes between version 4 and version 3 are to the + attribute structure to make it more flexible for non-unix platforms. + + o Clarify the use of stderr by the server. + + o Clarify handling of very large read requests by the server. + + o Make all filenames UTF-8. + + o Added 'newline' extension. + + o Made time fields 64 bit, and optionally have nanosecond resultion. + + o Made file attribute owner and group strings so they can actually + be used on disparate systems. + + o Added createtime field, and added separate flags for atime, + createtime, and mtime so they can be set separately. + + o Split the file type out of the permissions field and into it's own + field (which is always present.) + + o Added acl attribute. + + o Added SSH_FXF_TEXT file open flag. + + o Added flags field to the get stat commands so that the client can + specifically request information the server might not normally + included for performance reasons. + + o Removed the long filename from the names structure-- it can now be + built from information available in the attrs structure. + + o Added reserved range of packet numbers for extensions. + + o Added several additional error codes. + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 32] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +10.2 Changes between versions 3 and 2 + + o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. + + o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were + added. + + o The SSH_FXP_STATUS message was changed to include fields `error + message' and `language tag'. + + +10.3 Changes between versions 2 and 1 + + o The SSH_FXP_RENAME message was added. + + +10.4 Changes between versions 1 and 0 + + o Implementation changes, no actual protocol changes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 33] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +11. Trademark Issues + + "ssh" is a registered trademark of SSH Communications Security Corp + in the United States and/or other countries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 34] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +References + + [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and + P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January + 1999. + + [2] Alvestrand, H., "IETF Policy on Character Sets and Languages", + BCP 18, RFC 2277, January 1998. + + [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, + C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC + 3010, December 2000. + + [4] Institute of Electrical and Electronics Engineers, "Information + Technology - Portable Operating System Interface (POSIX) - Part + 1: System Application Program Interface (API) [C Language]", + IEEE Standard 1003.2, 1996. + + [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Architecture", + draft-ietf-secsh-architecture-13 (work in progress), September + 2002. + + [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Transport Protocol", + draft-ietf-secsh-transport-15 (work in progress), September + 2002. + + [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16 + (work in progress), September 2002. + + [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Authentication Protocol", + draft-ietf-secsh-userauth-16 (work in progress), September 2002. + + +Authors' Addresses + + Joseph Galbraith + VanDyke Software + 4848 Tramway Ridge Blvd + Suite 101 + Albuquerque, NM 87111 + US + + Phone: +1 505 332 5700 + EMail: galb-list@vandyke.com + + + +Galbraith, et al. Expires June 18, 2003 [Page 35] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: ylo@ssh.com + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 36] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + + + +Galbraith, et al. Expires June 18, 2003 [Page 37] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 38] + + diff --git a/doc/draft-ietf-secsh-fingerprint-01.txt b/doc/draft-ietf-secsh-fingerprint-01.txt new file mode 100644 index 00000000..5edea39d --- /dev/null +++ b/doc/draft-ietf-secsh-fingerprint-01.txt @@ -0,0 +1,120 @@ + + + + + + +INTERNET-DRAFT Markus Friedl +draft-ietf-secsh-fingerprint-01.txt The OpenBSD Project +Expires in six months September 2003 + + + SSH Fingerprint Format + + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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 docu- ments at + any time. It is inappropriate to use Internet- Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + Distribution of this memo is unlimited. + +Abstract + + This document formally documents the fingerprint format in use for + verifying public keys from SSH clients and servers. + +Introduction + + The security of the SSH protocols relies on the verification of + public host keys. Since public keys tend to be very large, it is + difficult for a human to verify an entire host key. Even with a PKI + in place, it is useful to have a standard for exchanging short + fingerprints of public keys. + + This document formally describes the simple key fingerprint format. + + + + + + +Friedl [Page 1] + + + + + +INTERNET-DRAFT March 2003 + + +Fingerprint Format + + The fingerprint of a public key consists of the output of the MD5 + message-digest algorithm [RFC-1321]. The input to the algorithm is + the public key blob as described in [SSH-TRANS]. The output of the + algorithm is presented to the user as a sequence of 16 octets printed + as hexadecimal with lowercase letters and separated by colons. + + For example: "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" + +References + + [SSH-TRANS] Ylonen, T., et al: "SSH Transport Layer Protocol", + Internet Draft, draft-secsh-transport-15.txt + + [RFC-1321] R. Rivest: "The MD5 Message-Digest Algorithm", April 1992. + + [RFC-2026] S. Bradner: "The Internet Standards Process -- Revision + 3", October 1996. + +Author's Address: + + Markus Friedl + markus@openbsd.org + Munich, Germany + + + + + + + + + + + + + + + + + + + + + + + + + + +Friedl [Page 2] + + diff --git a/doc/draft-ietf-secsh-gsskeyex-06.txt b/doc/draft-ietf-secsh-gsskeyex-06.txt new file mode 100644 index 00000000..da442579 --- /dev/null +++ b/doc/draft-ietf-secsh-gsskeyex-06.txt @@ -0,0 +1,1509 @@ + + +Network Working Group J. Hutzelman +Internet-Draft CMU +Expires: August 31, 2003 J. Salowey + Cisco Systems + J. Galbraith + Van Dyke Technologies, Inc. + V. Welch + U Chicago / ANL + March 2, 2003 + + + GSSAPI Authentication and Key Exchange for the Secure Shell Protocol + draft-ietf-secsh-gsskeyex-06 + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on August 31, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + The Secure Shell protocol (SSH) is a protocol for secure remote + login and other secure network services over an insecure network. + + The Generic Security Service Application Program Interface (GSS-API) + [2] provides security services to callers in a mechanism-independent + fashion. + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 1] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + This memo describes methods for using the GSS-API for authentication + and key exchange in SSH. It defines an SSH user authentication + method which uses a specified GSSAPI mechanism to authenticate a + user, and a family of SSH key exchange methods which use GSSAPI to + authenticate the Diffie-Hellman exchange described in [8]. + + This memo also defines a new host public key algorithm which can be + used when no operations are needed using a host's public key, and a + new user authentication method which allows an authorization name to + be used in conjunction with any authentication which has already + occurred as a side-effect of key exchange. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [5]. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 2] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +1. Introduction + + This document describes the methods used to perform key exchange and + user authentication in the Secure Shell protocol using the GSSAPI. + To do this, it defines a family of key exchange methods, two user + authentication methods, and a new host key algorithm. These + definitions allow any GSSAPI mechanism to be used with the Secure + Shell protocol. + + This document should be read only after reading the documents + describing the SSH protocol architecture [6], transport layer + protocol [8], and user authentication protocol [9]. This document + freely uses terminology and notation from the architecture document + without reference or further explanation. + +1.1 SSH terminology + + The data types used in the packets are defined in the SSH + architecture document [6]. It is particularly important to note the + definition of string allows binary content. + + The SSH_MSG_USERAUTH_REQUEST packet refers to a service; this + service name is an SSH service name, and has no relationship to + GSSAPI service names. Currently, the only defined service name is + "ssh-connection", which refers to the SSH connection protocol [7]. + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 3] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +2. GSSAPI Authenticated Diffie-Hellman Key Exchange + + This section defines a class of key exchange methods which combine + the Diffie-Hellman key exchange from section 6 of [8] with mutual + authentication using GSSAPI. + + Since the GSSAPI key exchange methods described in this section do + not require the use of public key signature or encryption + algorithms, they MAY be used with any host key algorithm, including + the "null" algorithm described in Section 5. + +2.1 Generic GSSAPI Key Exchange + + The following symbols are used in this description: + + o C is the client, and S is the server + + o p is a large safe prime, g is a generator for a subgroup of + GF(p), and q is the order of the subgroup + + o V_S is S's version string, and V_C is C's version string + + o I_C is C's KEXINIT message, and I_S is S's KEXINIT message + + 1. C generates a random number x (1 < x < q) and computes e = g^x + mod p. + + 2. C calls GSS_Init_sec_context, using the most recent reply token + received from S during this exchange, if any. For this call, + the client MUST set the mutual_req_flag to "true" to request + that mutual authentication be performed. It also MUST set the + integ_req_flag to "true" to request that per-message integrity + protection be supported for this context. In addition, the + deleg_req_flag MAY be set to "true" to request access + delegation, if requested by the user. Since the key exchange + process authenticates only the host, the setting of the + anon_req_flag is immaterial to this process. If the client does + not support the "external-keyx" user authentication method + described in Section 4, or does not intend to use that method, + then the anon_req_flag SHOULD be set to "true". Otherwise, this + flag MAY be set to true if the client wishes to hide its + identity. + + * If the resulting major_status code is GSS_S_COMPLETE and the + mutual_state flag is not true, then mutual authentication has + not been established, and the key exchange MUST fail. + + * If the resulting major_status code is GSS_S_COMPLETE and the + integ_avail flag is not true, then per-message integrity + + +Hutzelman, et. al. Expires August 31, 2003 [Page 4] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + protection is not available, and the key exchange MUST fail. + + * If the resulting major_status code is GSS_S_COMPLETE and both + the mutual_state and integ_avail flags are true, the + resulting output token is sent to S. + + * If the resulting major_status code is GSS_S_CONTINUE_NEEDED, + the the output_token is sent to S, which will reply with a + new token to be provided to GSS_Init_sec_context. + + * The client MUST also include "e" with the first message it + sends to the server during this process; if the server + receives more than one "e" or none at all, the key exchange + fails. + + * It is an error if the call does not produce a token of + non-zero length to be sent to the server. In this case, the + key exchange MUST fail. + + 3. S calls GSS_Accept_sec_context, using the token received from C. + + * If the resulting major_status code is GSS_S_COMPLETE and the + mutual_state flag is not true, then mutual authentication has + not been established, and the key exchange MUST fail. + + * If the resulting major_status code is GSS_S_COMPLETE and the + integ_avail flag is not true, then per-message integrity + protection is not available, and the key exchange MUST fail. + + * If the resulting major_status code is GSS_S_COMPLETE and both + the mutual_state and integ_avail flags are true, then the + security context has been established, and processing + continues with step 4. + + * If the resulting major_status code is GSS_S_CONTINUE_NEEDED, + then the output token is sent to C, and processing continues + with step 2. + + * If the resulting major_status code is GSS_S_COMPLETE, but a + non-zero-length reply token is returned, then that token is + sent to the client. + + 4. S generates a random number y (0 < y < q) and computes f = g^y + mod p. It computes K = e ^ y mod p, and H = hash(V_C || V_S || + I_C || I_S || K_S || e || f || K). It then calls GSS_GetMIC to + obtain a GSSAPI message integrity code for H. S then sends f + and the MIC to C. + + 5. This step is performed only if the server's final call to + + +Hutzelman, et. al. Expires August 31, 2003 [Page 5] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + GSS_Accept_sec_context produced a non-zero-length final reply + token to be sent to the client _and_ no previous call by the + client to GSS_Init_sec_context has resulted in a major_status of + GSS_S_COMPLETE. Under these conditions, the client makes an + additional call to GSS_Init_sec_context to process the final + reply token. This call is made exactly as described above. + However, if the resulting major_status is anything other than + GSS_S_COMPLETE, or a non-zero-length token is returned, it is an + error and the key exchange MUST fail. + + 6. C computes K = f^x mod p, and H = hash(V_C || V_S || I_C || I_S + || K_S || e || f || K). It then calls GSS_VerifyMIC to verify + that the MIC sent by S matches H. + + Either side MUST NOT send or accept e or f values that are not in + the range [1, p-1]. If this condition is violated, the key exchange + fails. + + If any call to GSS_Init_sec_context or GSS_Accept_sec_context + returns a major_status other than GSS_S_COMPLETE or + GSS_S_CONTINUE_NEEDED, or any other GSSAPI call returns a + major_status other than GSS_S_COMPLETE, the key exchange fails. In + this case, several mechanisms are available for communicating error + information to the peer before terminating the connection as + required by [8]: + + o If the key exchange fails due to any GSSAPI error on the server + (including errors returned by GSS_Accept_sec_context), the server + MAY send a message informing the client of the details of the + error. In this case, if an error token is also sent (see below), + then this message MUST be sent before the error token. + + o If the key exchange fails due to a GSSAPI error returned from the + server's call to GSS_Accept_sec_context, and an "error token" is + also returned, then the server SHOULD send the error token to the + client to allow completion of the GSS security exchange. + + o If the key exchange fails due to a GSSAPI error returned from the + client's call to GSS_Init_sec_context, and an "error token" is + also returned, then the client SHOULD send the error token to the + server to allow completion of the GSS security exchange. + + As noted in Section 9, it may be desirable under site security + policy to obscure information about the precise nature of the error; + thus, it is RECOMMENDED that implementations provide a method to + suppress these messages as a matter of policy. + + This is implemented with the following messages. The hash algorithm + for computing the exchange hash is defined by the method name, and + + +Hutzelman, et. al. Expires August 31, 2003 [Page 6] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + is called HASH. The group used for Diffie-Hellman key exchange and + the underlying GSSAPI mechanism are also defined by the method name. + + After the client's first call to GSS_Init_sec_context, it sends the + following: + + byte SSH_MSG_KEXGSS_INIT + string output_token (from GSS_Init_sec_context) + mpint e + + Upon receiving the SSH_MSG_KEXGSS_INIT message, the server MAY send + the following message, prior to any other messages, to inform the + client of its host key. + + byte SSH_MSG_KEXGSS_HOSTKEY + string server public host key and certificates (K_S) + + Since this key exchange method does not require the host key to be + used for any encryption operations, this message is OPTIONAL. If + the "null" host key algorithm described in Section 5 is used, this + message MUST NOT be sent. If this message is sent, the server + public host key(s) and/or certificate(s) in this message are encoded + as a single string, in the format specified by the public key type + in use (see [8], section 4.6). + + Each time the server's call to GSS_Accept_sec_context returns a + major_status code of GSS_S_CONTINUE_NEEDED, it sends the following + reply to the client: + + byte SSH_MSG_KEXGSS_CONTINUE + string output_token (from GSS_Accept_sec_context) + + If the client receives this message after a call to + GSS_Init_sec_context has returned a major_status code of + GSS_S_COMPLETE, a protocol error has occurred and the key exchange + MUST fail. + + Each time the client receives the message described above, it makes + another call to GSS_Init_sec_context. It then sends the following: + + byte SSH_MSG_KEXGSS_CONTINUE + string output_token (from GSS_Init_sec_context) + + The server and client continue to trade these two messages as long + as the server's calls to GSS_Accept_sec_context result in + major_status codes of GSS_S_CONTINUE_NEEDED. When a call results in + a major_status code of GSS_S_COMPLETE, it sends one of two final + messages. + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 7] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + If the server's final call to GSS_Accept_sec_context (resulting in a + major_status code of GSS_S_COMPLETE) returns a non-zero-length token + to be sent to the client, it sends the following: + + byte SSH_MSG_KEXGSS_COMPLETE + mpint f + string per_msg_token (MIC of H) + boolean TRUE + string output_token (from GSS_Accept_sec_context) + + If the client receives this message after a call to + GSS_Init_sec_context has returned a major_status code of + GSS_S_COMPLETE, a protocol error has occurred and the key exchange + MUST fail. + + If the server's final call to GSS_Accept_sec_context (resulting in a + major_status code of GSS_S_COMPLETE) returns a zero-length token or + no token at all, it sends the following: + + byte SSH_MSG_KEXGSS_COMPLETE + mpint f + string per_msg_token (MIC of H) + boolean FALSE + + If the client receives this message when no call to + GSS_Init_sec_context has yet resulted in a major_status code of + GSS_S_COMPLETE, a protocol error has occurred and the key exchange + MUST fail. + + If either the client's call to GSS_Init_sec_context or the server's + call to GSS_Accept_sec_context returns an error status and produces + an output token (called an "error token"), then the following SHOULD + be sent to convey the error information to the peer: + + byte SSH_MSG_KEXGSS_CONTINUE + string error_token + + If a server sends both this message and an SSH_MSG_KEXGSS_ERROR + message, the SSH_MSG_KEXGSS_ERROR message MUST be sent first, to + allow clients to record and/or display the error information before + processing the error token. This is important because a client + processing an error token will likely disconnect without reading any + further messages. + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 8] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + In the event of a GSSAPI error on the server, the server MAY send + the following message before terminating the connection: + + byte SSH_MSG_KEXGSS_ERROR + uint32 major_status + uint32 minor_status + string message + string language tag + + The message text MUST be encoded in the UTF-8 encoding described in + [10]. Language tags are those described in [11]. Note that the + message text may contain multiple lines separated by carriage + return-line feed (CRLF) sequences. Application developers should + take this into account when displaying these messages. + + The hash H is computed as the HASH hash of the concatenation of the + following: + + string V_C, the client's version string (CR and NL excluded) + string V_S, the server's version string (CR and NL excluded) + string I_C, the payload of the client's SSH_MSG_KEXINIT + string I_S, the payload of the server's SSH_MSG_KEXINIT + string K_S, the host key + mpint e, exchange value sent by the client + mpint f, exchange value sent by the server + mpint K, the shared secret + + This value is called the exchange hash, and it is used to + authenticate the key exchange. The exchange hash SHOULD be kept + secret. If no SSH_MSG_KEXGSS_HOSTKEY message has been sent by the + server or received by the client, then the empty string is used in + place of K_S when computing the exchange hash. + + The GSS_GetMIC call MUST be applied over H, not the original data. + +2.2 gss-group1-sha1-* + + Each of these methods specifies GSSAPI authenticated Diffie-Hellman + key exchange as described in Section 2.1 with SHA-1 as HASH, and the + group defined in section 6.1 of [8]. The method name for each + method is the concatenation of the string "gss-group1-sha1-" with + the Base64 encoding of the MD5 hash [3] of the ASN.1 DER encoding + [1] of the underlying GSSAPI mechanism's OID. Base64 encoding is + described in section 6.8 of [4]. + + Each and every such key exchange method is implicitly registered by + this specification. The IESG is considered to be the owner of all + such key exchange methods; this does NOT imply that the IESG is + considered to be the owner of the underlying GSSAPI mechanism. + + +Hutzelman, et. al. Expires August 31, 2003 [Page 9] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +2.3 Other GSSAPI key exchange methods + + Key exchange method names starting with "gss-" are reserved for key + exchange methods which conform to this document; in particular, for + those methods which use the GSSAPI authenticated Diffie-Hellman key + exchange algorithm described in Section 2.1, including any future + methods which use different groups and/or hash functions. The + intent is that the names for any such future methods methods be + defined in a similar manner to that used in Section 2.2. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 10] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +3. GSSAPI User Authentication + + This section describes a general-purpose user authentication method + based on [2]. It is intended to be run over the SSH user + authentication protocol [9]. + + The authentication method name for this protocol is "gssapi". + +3.1 GSSAPI Authentication Overview + + GSSAPI authentication must maintain a context. Authentication + begins when the client sends a SSH_MSG_USERAUTH_REQUEST, which + specifies the mechanism OIDs the client supports. + + If the server supports any of the requested mechanism OIDs, the + server sends a SSH_MSG_USERAUTH_GSSAPI_RESPONSE message containing + the mechanism OID. + + After the client receives SSH_MSG_USERAUTH_GSSAPI_RESPONSE, the + client and server exchange SSH_MSG_USERAUTH_GSSAPI_TOKEN packets + until the authentication mechanism either succeeds or fails. + + If at any time during the exchange, the client sends a new + SSH_MSG_USERAUTH_REQUEST packet, the GSSAPI context is completely + discarded and destroyed, and any further GSSAPI authentication MUST + restart from the beginning. + +3.2 Initiating GSSAPI authentication + + The GSSAPI authentication method is initiated when the client sends + a SSH_MSG_USERAUTH_REQUEST: + + byte SSH_MSG_USERAUTH_REQUEST + string user name (in ISO-10646 UTF-8 encoding) + string service name (in US-ASCII) + string "gssapi" (US-ASCII method name) + uint32 n, the number of mechanism OIDs client supports + string[n] mechanism OIDs + + Mechanism OIDs are encoded according to the ASN.1 distinguished + encoding rules (DER), as described in [1] and in section 3.1 of [2]. + The mechanism OIDs MUST be listed in order of preference, and the + server must choose the first mechanism OID on the list that it + supports. + + The client SHOULD NOT send more then one gssapi mechanism OID unless + there are no non-GSSAPI authentication methods between the GSSAPI + mechanisms in the order of preference, otherwise, authentication + methods may be executed out of order. + + +Hutzelman, et. al. Expires August 31, 2003 [Page 11] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + If the server does not support any of the specified OIDs, the server + MUST fail the request by sending a SSH_MSG_USERAUTH_FAILURE packet. + + The user name may be an empty string if it can be deduced from the + results of the gssapi authentication. If the user name is not + empty, and the requested user does not exist, the server MAY + disconnect, or MAY send a bogus list of acceptable authentications + but never accept any. This makes it possible for the server to + avoid disclosing information about which accounts exist. In any + case, if the user does not exist, the authentication request MUST + NOT be accepted. + + The client MAY at any time continue with a new + SSH_MSG_USERAUTH_REQUEST message, in which case the server MUST + abandon the previous authentication attempt and continue with the + new one. + +3.3 Initial server response + + The server responds to the SSH_MSG_USERAUTH_REQUEST with either a + SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported, or + with SSH_MSG_USERAUTH_GSSAPI_RESPONSE as follows: + + byte SSH_MSG_USERAUTH_GSSAPI_RESPONSE + string selected mechanism OID + + The mechanism OID must be one of the OIDs sent by the client in the + SSH_MSG_USERAUTH_REQUEST packet. + +3.4 GSSAPI session + + Once the mechanism OID has been selected, the client will then + initiate an exchange of one or more pairs of + SSH_MSG_USERAUTH_GSSAPI_TOKEN packets. These packets contain the + tokens produced from the 'GSS_Init_sec_context()' and + 'GSS_Accept_sec_context()' calls. The actual number of packets + exchanged is determined by the underlying GSSAPI mechanism. + + byte SSH_MSG_USERAUTH_GSSAPI_TOKEN + string data returned from either GSS_Init_sec_context() + or GSS_Accept_sec_context() + + If an error occurs during this exchange on server side, the server + can terminate the method by sending a SSH_MSG_USERAUTH_FAILURE + packet. If an error occurs on client side, the client can terminate + the method by sending a new SSH_MSG_USERAUTH_REQUEST packet. + + The client MAY use the deleg_req_flag in calls to + GSS_Init_sec_context() to request credential delegation. + + +Hutzelman, et. al. Expires August 31, 2003 [Page 12] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + Additional SSH_MSG_USERAUTH_GSSAPI_TOKEN messages are sent if and + only if the calls to the GSSAPI routines produce send tokens of + non-zero length. + + Any major status code other than GSS_S_COMPLETE or + GSS_S_CONTINUE_NEEDED SHOULD be a failure. + +3.5 Client acknowledgement + + It is possible for the server to successfully complete the GSSAPI + method and the client to fail. If the server simply assumed success + on the part of the client and completed the authentication service, + it is possible that the client would fail to complete the + authentication method, but not be able to retry other methods + because the server had already moved on. + + Therefore, the client MUST send the following message when it has + successfully called GSS_Init_sec_context() and gotten GSS_S_COMPLETE: + + byte SSH_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE + + This message MUST be sent if and only if GSS_Init_sec_context() + returned GSS_S_COMPLETE. If a token is returned then the + SSH_MSG_USERAUTH_GSSAPI_TOKEN message MUST be sent before this one. + + If GSS_Init_sec_context() failed, the client MUST terminate the + method by sending a new SSH_MSG_USERAUTH_REQUEST. or by closing the + connection + +3.6 Completion + + As with all SSH authentication methods, successful completion is + indicated by a SSH_MSG_USERAUTH_SUCCESS if no other authentication + is required, or a SSH_MSG_USERAUTH_FAILURE with the partial success + flag set if the server requires further authentication. + + This packet should be sent immediately following receipt of the the + SSH_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE packet. + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 13] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +3.7 Error Status + + In the event a GSSAPI error occurs on the server during context + establishment, the server MAY send the following message to inform + the client of the details of the error before sending a + SSH_MSG_USERAUTH_FAILURE message: + + byte SSH_MSG_USERAUTH_GSSAPI_ERROR + uint32 major_status + uint32 minor_status + string message + string language tag + + The message text MUST be encoded in the UTF-8 encoding described in + [10]. Language tags are those described in [11]. Note that the + message text may contain multiple lines separated by carriage + return-line feed (CRLF) sequences. Application developers should + take this into account when displaying these messages. + + Clients receiving this message MAY log the error details and/or + report them to the user. Any server sending this message MUST + ignore any SSH_MSG_UNIMPLEMENTED sent by the client in response. + +3.8 Error Token + + In the event that, during context establishment, a client's call to + GSS_Init_sec_context or a server's call to GSS_Accept_sec_context + returns a token along with an error status, the resulting "error + token" SHOULD be sent to the peer using the following message: + + byte SSH_MSG_USERAUTH_GSSAPI_ERRTOK + string error token + + This message implies that the authentication is about to fail, and + is defined to allow the error token to be communicated without + losing synchronization. + + When a server sends this message, it MUST be followed by a + SSH_MSG_USERAUTH_FAILURE message, which is to be interpreted as + applying to the same authentication request. A client receiving + this message SHOULD wait for the following SSH_MSG_USERAUTH_FAILURE + message before beginning another authentication attempt. + + When a client sends this message, it MUST be followed by a new + authentication request or by terminating the connection. A server + receiving this message MUST NOT send a SSH_MSG_USERAUTH_FAILURE in + reply, since such a message might otherwise be interpreted by a + client as a response to the following authentication sequence. + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 14] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + Any server sending this message MUST ignore any + SSH_MSG_UNIMPLEMENTED sent by the client in response. If a server + sends both this message and an SSH_MSG_USERAUTH_GSSAPI_ERROR + message, the SSH_MSG_USERAUTH_GSSAPI_ERROR message MUST be sent + first, to allow the client to store and/or display the error status + before processing the error token. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 15] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +4. External Key Exchange User Authentication + + This section describes a user authentication method building on the + framework described in [9]. This method relies upon the key + exchange to authenticate both the client and the server. If the key + exchange did not successfully perform these functions then the + server MUST always respond to this request with + SSH_MSG_USERAUTH_FAILURE with partial success set to false. + + The new mechanism is defined as follows: + + byte SSH_MSG_USERAUTH_REQUEST + string user name (in ISO-10646 UTF-8 encoding) + string service name (in US-ASCII) + string "external-keyx" (US-ASCII method name) + + If the authentication performed as part of key exchange can be used + to authorize login as the requested user, this method is successful, + and the server responds with SSH_MSG_USERAUTH_SUCCESS if no more + authentications are needed, or with SSH_MSG_USERAUTH_FAILURE with + partial success set to true if more authentications are needed. + + If the authentication performed as part of key-exchange cannot be + used to authorize login as the requested user, then + SSH_MSG_USERAUTH_FAILURE is returned with partial success set to + false. + + If the user name is not empty, and the requested user does not + exist, the server MAY disconnect, or MAY send a bogus list of + acceptable authentications but never accept any. This makes it + possible for the server to avoid disclosing information about which + accounts exist. In any case, if the user does not exist, the + authentication request MUST NOT be accepted. + + Any implementation supporting at least one key exchange method which + conforms to section 1 of this document SHOULD also support the + "external-keyx" user authentication method, in order to allow user + authentication to be performed at the same time as key exchange, + thereby reducing the number of round trips needed for connection + setup. + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 16] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +5. Null Host Key Algorithm + + The "null" host key algorithm has no associated host key material, + and provides neither signature nor encryption algorithms. Thus, it + can be used only with key exchange methods that do not require any + public-key operations and do not require the use of host public key + material. The key exchange methods described in section 1 of this + document are examples of such methods. + + This algorithm is used when, as a matter of configuration, the host + does not have or does not wish to use a public key. For example, it + can be used when the administrator has decided as a matter of policy + to require that all key exchanges be authenticated using Kerberos + [12], and thus the only permitted key exchange method is the + GSSAPI-authenticated Diffie-Hellman exchange described above, with + Kerberos V5 as the underlying GSSAPI mechanism. In such a + configuration, the server implementation supports the "ssh-dss" key + algorithm (as required by [8]), but could be prohibited by + configuration from using it. In this situation, the server needs + some key exchange algorithm to advertise; the "null" algorithm fills + this purpose. + + Note that the use of the "null" algorithm in this way means that the + server will not be able to interoperate with clients which do not + support this algorithm. This is not a significant problem, since in + the configuration described, it will also be unable to interoperate + with implementations that do not support the GSSAPI-authenticated + key exchange and Kerberos. + + Any implementation supporting at least one key exchange method which + conforms to section 1 of this document MUST also support the "null" + host key algorithm. Servers MUST NOT advertise the "null" host key + algorithm unless it is the only algorithm advertised. + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 17] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +6. Summary of Message Numbers + + The following message numbers have been defined for use with + GSSAPI-based key exchange methods: + + #define SSH_MSG_KEXGSS_INIT 30 + #define SSH_MSG_KEXGSS_CONTINUE 31 + #define SSH_MSG_KEXGSS_COMPLETE 32 + #define SSH_MSG_KEXGSS_HOSTKEY 33 + #define SSH_MSG_KEXGSS_ERROR 34 + + The numbers 30-49 are specific to key exchange and may be redefined + by other kex methods. + + The following message numbers have been defined for use with the + 'gssapi' user authentication method: + + #define SSH_MSG_USERAUTH_GSSAPI_RESPONSE 60 + #define SSH_MSG_USERAUTH_GSSAPI_TOKEN 61 + #define SSH_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 + #define SSH_MSG_USERAUTH_GSSAPI_ERROR 64 + + The numbers 60-79 are specific to user authentication and may be + redefined by other user auth methods. Note that in the method + described in this document, message number 62 is unused. + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 18] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +7. GSSAPI Considerations + +7.1 Naming Conventions + + In order to establish a GSSAPI security context, the SSH client + needs to determine the appropriate targ_name to use in identifying + the server when calling GSS_Init_sec_context. For this purpose, the + GSSAPI mechanism-independent name form for host-based services is + used, as described in section 4.1 of [2]. + + In particular, the targ_name to pass to GSS_Init_sec_context is + obtained by calling GSS_Import_name with an input_name_type of + GSS_C_NT_HOSTBASED_SERVICE, and an input_name_string consisting of + the string "host@" concatenated with the hostname of the SSH server. + +7.2 Channel Bindings + + This document recommends that channel bindings SHOULD NOT be + specified in the calls during context establishment. This document + does not specify any standard data to be used as channel bindings + and the use of network addresses as channel bindings may break SSH + in environments where it is most useful. + +7.3 SPNEGO + + The use of the Simple and Protected GSS-API Negotiation Mechanism + [14] in conjunction with the authentication and key exchange methods + described in this document is both unnecessary and undesirable. As + a result, mechanisms conforming to this document MUST NOT use SPNEGO + as the underlying GSSAPI mechanism. + + Since SSH performs its own negotiation of authentication and key + exchange methods, the negotiation capability of SPNEGO alone does + not provide any added benefit. In fact, as described below, it has + the potential to result in the use of a weaker method than desired. + + Normally, SPNEGO provides the added benefit of protecting the GSSAPI + mechanism negotiation. It does this by having the server compute a + MIC of the list of mechanisms proposed by the client, and then + checking that value at the client. In the case of key exchange, + this protection is not needed because the key exchange methods + described here already perform an equivalent operation; namely, they + generate a MIC of the SSH exchange hash, which is a hash of several + items including the lists of key exchange mechanisms supported by + both sides. In the case of user authentication, the protection is + not needed because the negotiation occurs over a secure channel, and + the host's identity has already been proved to the user. + + The use of SPNEGO combined with GSSAPI mechanisms used without + + +Hutzelman, et. al. Expires August 31, 2003 [Page 19] + +Internet-Draft SSH GSSAPI Methods March 2003 + + + SPNEGO can lead to interoperability problems. For example, a client + which supports key exchange using the Kerberos V5 GSSAPI mechanism + [13] only underneath SPNEGO will not interoperate with a server + which supports key exchange only using the Kerberos V5 GSSAPI + mechanism directly. As a result, allowing GSSAPI mechanisms to be + used both with and without SPNEGO is undesirable. + + If a client's policy is to first prefer GSSAPI-based key exchange + method X, then non-GSSAPI method Y, then GSSAPI-based method Z, and + if a server supports mechanisms Y and Z but not X, then an attempt + to use SPNEGO to negotiate a GSSAPI mechanism might result in the + use of method Z when method Y would have been preferable. As a + result, the use of SPNEGO could result in the subversion of the + negotiation algorithm for key exchange methods as described in + section 5.1 of [8] and/or the negotiation algorithm for user + authentication methods as described in [9]. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 20] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +8. IANA Considerations + + Consistent with section 7 of [6], the IANA is directed to make the + following registrations: + + The family of SSH key exchange method names beginning with + "gss-group1-sha1-" and not containing the at-sign ('@'), to name + the key exchange methods defined in Section 2.2. + + All other SSH key exchange method names beginning with "gss-" and + not containing the at-sign ('@'), to be reserved for future key + exchange methods defined in conformance with this document, as + noted in Section 2.3. + + The SSH host public key algorithm name "null", to name the NULL + host key algorithm defined in Section 5. + + The SSH user authentication method name "gssapi", to name the + GSSAPI user authentication method defined in Section 3. + + The SSH user authentication method name "external-keyx", to name + the "external key-exchange" user authentication method defined in + Section 4. + + This document creates no new registries. + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 21] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +9. Security Considerations + + This document describes authentication and key-exchange protocols. + As such, security considerations are discussed throughout. + + This protocol depends on the SSH protocol itself, the GSSAPI, any + underlying GSSAPI mechanisms which are used, and any protocols on + which such mechanisms might depend. Each of these components plays + a part in the security of the resulting connection, and each will + have its own security considerations. + + The key exchange method described in section 1 of this document + depends on the underlying GSSAPI mechanism to provide both mutual + authentication and per-message integrity services. If either of + these features is not supported by a particular GSSAPI mechanism, or + by a particular implementation of a GSSAPI mechanism, then the key + exchange is not secure and MUST fail. + + In order for the "external-keyx" user authentication method to be + used, it MUST have access to user authentication information + obtained as a side-effect of the key exchange. If this information + is unavailable, the authentication MUST fail. + + Revealing information about the reason for an authentication failure + may be considered by some sites to be an unacceptable security risk + for a production environment. However, having that information + available can be invaluable for debugging purposes. Thus, it is + RECOMMENDED that implementations provide a means for controlling, as + a matter of policy, whether to send SSH_MSG_USERAUTH_GSSAPI_ERROR, + SSH_MSG_USERAUTH_GSSAPI_ERRTOK, and SSH_MSG_KEXGSS_ERROR messages, + and SSH_MSG_KEXGEE_CONTINUE messages containing a GSSAPI error token. + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 22] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +10. Acknowledgements + + The authors would like to thank Sam Hartman, Simon Wilkinson, and + Nicolas Williams for their invaluable assistance with this document. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 23] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +11. Changes the last version + + This section lists important changes since the previous version of + this internet-draft. This section should be removed at the time of + publication of this document as an RFC. + + o Improved the description of error handling during key exchange. + + o Specified that SSH_MSG_GSSKEX_CONTINUE SHOULD be used to send + error tokens in the event of a failure of GSS_Init_sec_context or + GSS_Accept_sec_context during key exchange. + + o Made SSH_MSG_GSSKEX_ERROR be OPTIONAL instead of RECOMMENDED. + + o Specified a new SSH_MSG_USERAUTH_GSSAPI_ERRTOK message which + SHOULD be used to send error tokens in the event of a failure of + GSS_Init_sec_context or GSS_Accept_sec_context during user + authentication. + + o Made SSH_MSG_USERAUTH_GSSAPI_ERROR be OPTIONAL instead of + RECOMMENDED. + + o Added IANA considerations section. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 24] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +Normative References + + [1] ISO/IEC, "ASN.1 Encoding Rules: Specification of Basic + Encoding Rules (BER), Canonical Encoding Rules (CER) and + Distinguished Encoding Rules (DER)", ITU-T Recommendation + X.690 (1997), ISO/IEC 8825-1:1998, November 1998. + + [2] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [3] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, + April 1992. + + [4] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [5] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", RFC 2119, BCP 14, March 1997. + + [6] Ylonen, T., Kivinen, T., Saarinen, M., Rinne, T. and S. + Lehtinen, "SSH Protocol Architecture", + draft-ietf-secsh-architecture-11.txt (work in progress), + November 2001. + + [7] Ylonen, T., Kivinen, T., Saarinen, M., Rinne, T. and S. + Lehtinen, "SSH Connection Protocol", + draft-ietf-secsh-connect-14.txt (work in progress), November + 2001. + + [8] Ylonen, T., Kivinen, T., Saarinen, M., Rinne, T. and S. + Lehtinen, "SSH Transport Layer Protocol", + draft-ietf-secsh-transport-11.txt (work in progress), November + 2001. + + [9] Ylonen, T., Kivinen, T., Saarinen, M., Rinne, T. and S. + Lehtinen, "SSH Authentication Protocol", + draft-ietf-secsh-userauth-13.txt (work in progress), November + 2001. + + [10] Yergeau, F., "UTF-8, a transformation format of ISO 10646", + RFC 2279, January 1998. + + [11] Alvestrand, H., "Tags for the Identification of Languages", + RFC 1766, March 1995. + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 25] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +Non-normative References + + [12] Kohl, J. and C. Neuman, "The Kerberos Network Authentication + Service (V5)", RFC 1510, September 1993. + + [13] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC + 1964, June 1996. + + [14] Baize, E. and D. Pinkas, "The Simple and Protected GSS-API + Negotiation Mechanism", RFC 2478, December 1998. + + +Authors' Addresses + + Jeffrey Hutzelman + Carnegie Mellon University + 5000 Forbes Ave + Pittsburgh, PA 15213 + US + + Phone: +1 412 268 7225 + EMail: jhutz+@cmu.edu + URI: http://www.cs.cmu.edu/~jhutz/ + + + Joseph Salowey + Cisco Systems + 2901 Third Avenue + Seattle, WA 98121 + US + + Phone: +1 206 256 3380 + EMail: jsalowey@cisco.com + + + Joseph Galbraith + Van Dyke Technologies, Inc. + 4848 Tramway Ridge Dr. NE + Suite 101 + Albuquerque, NM 87111 + US + + EMail: galb@vandyke.com + + + Von Welch + University of Chicago & Argonne National Laboratory + Distributed Systems Laboratory + 701 E. Washington + Urbana, IL 61801 + US + + EMail: welch@mcs.anl.gov + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 26] + +Internet-Draft SSH GSSAPI Methods March 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph + are included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + +Hutzelman, et. al. Expires August 31, 2003 [Page 27] + diff --git a/doc/draft-ietf-secsh-newmodes-00.txt b/doc/draft-ietf-secsh-newmodes-00.txt new file mode 100644 index 00000000..1554ac35 --- /dev/null +++ b/doc/draft-ietf-secsh-newmodes-00.txt @@ -0,0 +1,619 @@ + + + + + + +Network Working Group M. Bellare +Internet-Draft T. Kohno +Expires: September 20, 2003 UC San Diego + C. Namprempre + Thammasat University + March 20, 2003 + + + SSH Transport Layer Encryption Modes + + draft-ietf-secsh-newmodes-00.txt + + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on September 20, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + Researchers have recently discovered that the authenticated + encryption portion of the current SSH Transport Protocol is + vulnerable to several attacks. + + This document describes new symmetric encryption methods for the SSH + Transport Protocol and gives specific recommendations on how + + + +Bellare, Kohno, and Namprempre [Page 1] + +Internet Draft Month, Year + + + frequently SSH implementations should rekey. + + Bellare, Kohno, and Namprempre [ACM CCS 2002] prove that if an SSH + application implements the modifications described in this document, + then the symmetric cryptographic portion of that application will + provably resist chosen-plaintext, chosen-ciphertext, reaction-based + privacy and integrity/authenticity attacks. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 2 + 3. Rekeying . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3.1 First Rekeying Recommendation . . . . . . . . . . . . . . . . 3 + 3.2 Second Rekeying Recommendation . . . . . . . . . . . . . . . . 3 + 4. Encryption Modes . . . . . . . . . . . . . . . . . . . . . . . 4 + 5. Security Considerations . . . . . . . . . . . . . . . . . . . 6 + 5.1 Rekeying Considerations . . . . . . . . . . . . . . . . . . . 7 + 5.2 Encryption Method Considerations . . . . . . . . . . . . . . . 8 + References . . . . . . . . . . . . . . . . . . . . . . . . . . 9 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 10 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . 10 + +1. Introduction + + The symmetric portion of the SSH Transport Protocol was designed to + provide both privacy and integrity of encapsulated data. Researchers + ([DAI,BKN]) have, however, recently identified several security + problems with the symmetric portion of the SSH Transport Protocol as + described in [SSH-TRANS]. For example, the encryption mode specified + in [SSH-TRANS] is vulnerable to a chosen-plaintext privacy attack. + Additionally, if not rekeyed frequently enough, the SSH Transport + Protocol may leak information about payload data. This latter + property is true regardless of what encryption mode is used. + + In [BKN] Bellare, Kohno, and Namprempre show how to modify the + symmetric portion of the SSH Transport Protocol so that it provably + preserves privacy and integrity against chosen-plaintext, chosen- + ciphertext, and reaction attacks. This document instantiates the + recommendations described in [BKN]. + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + The used data types and terminology are specified in the architecture + + + +Bellare, Kohno, and Namprempre [Page 2] + +Internet Draft Month, Year + + + document [SSH-ARCH]. + + The SSH Transport Protocol is specified in the transport document + [SSH-TRANS]. + +3. Rekeying + + Section 7 of [SSH-TRANS] suggests that SSH implementations rekey + after every gigabyte of transmitted data. [SSH-TRANS] does not, + however, discuss all the problems that could arise if an SSH + implementation does not rekey frequently enough. This section serves + to strengthen the suggestion in [SSH-TRANS] by giving firm upper + bounds on the tolerable number of encryptions between rekeying + operations. In Section 5 we discuss the motivation for these + rekeying recommendations in more detail. + + This section makes two recommendations. Informally, the first + recommendation is intended to protects against possible information + leakage through the MAC tag and the second recommendation is intended + to protect against possible information leakage through the block + cipher. Note that, depending on the block length of the underlying + block cipher and the length of the encrypted packets, the first + recommendation may supersede the second recommendation, or visa- + versa. + +3.1 First Rekeying Recommendation + + Because of possible information leakage through the MAC tag, SSH + implementations SHOULD rekey at least once every 2**32 outgoing + packets. More explicitly, after a key exchange an SSH implementation + SHOULD NOT send more than 2**32 packets before rekeying again. + + SSH implementations SHOULD also attempt to rekey before receiving + more than 2**32 packets since the last rekey operation. The + preferred way to do this is to rekey after receiving more than 2**31 + packets since the last rekey operation. + +3.2 Second Rekeying Recommendation + + Because of a birthday property of block ciphers and some modes of + operation, implementations must be careful not to encrypt too many + blocks with the same encryption key. + + Let L be the block length (in bits) of an SSH encryption method's + block cipher (eg, 128 for AES). If L is at least 128 then, after + rekeying, an SSH implementation SHOULD NOT encrypt more than 2**(L/4) + blocks before rekeying again. If L is at least 128, then SSH + implementations should also attempt to force a rekey before receiving + + + +Bellare, Kohno, and Namprempre [Page 3] + +Internet Draft Month, Year + + + more than 2**(L/4) blocks. If L is less than 128 (which is the case + for older ciphers such as 3DES, Blowfish, CAST-128, and IDEA), then, + although it may be too expensive to rekey every 2**(L/4) blocks, it + is still advisable for SSH implementations to follow the original + recommendation in [SSH-TRANS]: rekey at least once every gigabyte of + transmitted data. + + Note that if L is less than or equal to 128, then the recommendation + in this subsection supersedes the recommendation in Section 3.1. If + an SSH implementation uses a block cipher with a larger block size + (eg, Rijndael with 256-bit blocks), then the recommendations in the + above paragraph may supersede the recommendations in this paragraph + (depending on the lengths of the packets). + +4. Encryption Modes + + This document describes new encryption methods for use with the SSH + Transport Protocol. These encryption methods are in addition to the + encryption methods described in Section 4.3 of [SSH-TRANS]. + + Recall from [SSH-TRANS] that the encryption methods in each direction + of an SSH connection MUST run independently of each other and that, + when encryption is in effect, the packet length, padding length, + payload, and padding fields of each packet MUST be encrypted with the + chosen method. Further recall that the total length of the + concatenation of the packet length, padding length, payload, and + padding MUST be a multiple of the cipher's block size when the + cipher's block size is greater than or equal to 8 bytes (which is the + case for all of the following methods). + + This document describes the following new methods: + + aes128-ctr RECOMMENDED AES (Rijndael) in SDCTR mode, + with 128-bit key + aes192-ctr RECOMMENDED AES with 192-bit key + aes256-ctr RECOMMENDED AES with 256-bit key + 3des-ctr RECOMMENDED Three-key 3DES in SDCTR mode + blowfish-ctr RECOMMENDED Blowfish in SDCTR mode + twofish128-ctr RECOMMENDED Twofish in SDCTR mode, + with 128-bit key + twofish192-ctr OPTIONAL Twofish with 192-bit key + twofish256-ctr OPTIONAL Twofish with 256-bit key + serpent128-ctr RECOMMENDED Serpent in SDCTR mode, with + with 128-bit key + serpent192-ctr OPTIONAL Serpent with 192-bit key + serpent256-ctr OPTIONAL Serpent with 256-bit key + idea-ctr OPTIONAL IDEA in SDCTR mode + cast128-ctr OPTIONAL CAST-128 in SDCTR mode + + + +Bellare, Kohno, and Namprempre [Page 4] + +Internet Draft Month, Year + + + The label -ctr means that the block cipher is to be + used in "stateful-decryption counter" (SDCTR) mode. Let L be the + block length of in bits. In stateful-decryption counter + mode both the sender and the receiver maintain an internal L-bit + counter X. The initial value of X should be the initial IV (as + computed in Section 5.2 of [SSH-TRANS]) interpreted as an L-bit + unsigned integer in network-byte-order. If X=(2**L)-1, then + "increment X" has the traditional semantics of "set X to 0." We use + the notation to mean "convert X to an L-bit string in network- + byte-order." Naturally, implementations may differ in how the + internal value X is stored. For example, implementations may store X + as multiple unsigned 32-bit counters. + + To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each + blocks of length L), the encryptor first encrypts with + to obtain a block B1. The block B1 is then XORed with P1 to generate + the ciphertext block C1. The counter X is then incremented and the + process is repeated for each subsequent block in order to generate + the entire ciphertext C=C1||C2||...||Cn corresponding to the packet + P. Note that the counter X is not included in the ciphertext. Also + note that the keystream can be pre-computed and that encryption is + parallelizable. + + To decrypt a ciphertext C=C1||C2||...||Cn, the decryptor (who also + maintains its own copy of X), first encrypts its copy of with + to generate a block B1 and then XORs B1 to C1 to get P1. + The decryptor then increments its copy of the counter X and repeats + the above process for each block to obtain the plaintext packet + P=P1||P2||...||Pn. As before, the keystream can be pre-computed and + decryption is parallelizable. + + The "aes128-ctr" method uses AES (the Advanced Encryption Standard, + formerly Rijndael) with 128-bit keys [AES]. The block size is 16 + bytes. + + The "aes192-ctr" method uses AES with 192-bit keys. + + The "aes256-ctr" method uses AES with 256-bit keys. + + The "3des-ctr" method uses three-key triple-DES (encrypt-decrypt- + encrypt), where the first 8 bytes of the key are used for the first + encryption, the next 8 bytes for the decryption, and the following 8 + bytes for the final encryption. This requires 24 bytes of key data + (of which 168 bits are actually used). The block size is 8 bytes. + This algorithm is defined in [SCHNEIER]. + + The "blowfish-ctr" method uses Blowfish with 256 bit keys [SCHNEIER]. + The block size is 8 bytes. + + + +Bellare, Kohno, and Namprempre [Page 5] + +Internet Draft Month, Year + + + The "twofish128-ctr" method uses Twofish with 128-bit keys [TWOFISH]. + The block size is 16 bytes. + + The "twofish192-ctr" method uses Twofish with 192-bit keys. + + The "twofish256-ctr" method uses Twofish with 256-bit keys. + + The "serpent128-ctr" method uses the Serpent block cipher [SERPENT] + with 128-bit keys. The block size is 16 bytes. + + The "serpent192-ctr" method uses Serpent with 192-bit keys. + + The "serpent256-ctr" method uses Serpent with 256-bit keys. + + The "idea-ctr" method uses the IDEA cipher [SCHNEIER]. IDEA is + patented by Ascom AG. The block size is 8 bytes. + + The "cast128-ctr" method uses the CAST-128 cipher [RFC2144]. The + block size is 8 bytes. + +5. Security Considerations + + This document describes additional encryption methods and + recommendations for the SSH Transport Protocol [SSH-TRANS]. [BKN] + prove that if an SSH application incorporates the methods and + recommendations described in this document, then the symmetric + cryptographic portion of that application will resist a large class + of privacy and integrity attacks. + + This section is designed to help implementors understand the + security-related motivations for, as well as possible consequences of + deviating from, the methods and recommendations described in this + document. Additional motivation and discussion, as well as proofs of + security, appear in the research paper [BKN]. + + Please note that the notion of "prove" in the context of [BKN] is + that of practice-oriented reductionist security: if an attacker is + able to break the symmetric portion of the SSH Transport Protocol + using a certain type of attack (eg, a chosen-ciphertext attack), then + the attacker will also be able to break one of the transport + protocol's underlying components (eg, the underlying block cipher or + MAC). If we make the reasonable assumption that the underlying + components (such as AES and HMAC-SHA1) are secure, then the attacker + against the symmetric portion of the SSH protocol cannot be very + successful (since otherwise there would be a contradiction). Please + see [BKN] for details. In particular, attacks are not impossible; + just extremely improbable (unless the building blocks, like AES, are + insecure). + + + +Bellare, Kohno, and Namprempre [Page 6] + +Internet Draft Month, Year + + + Note also that cryptography often plays only a small (but critical) + role in an application's overall security. In the case of the SSH + Transport Protocol, even though an application might implement the + symmetric portion of the SSH protocol exactly as described in this + document, the application may still be vulnerable to non-protocol- + based attacks (as an egregious example, an application might save + cryptographic keys in cleartext to an unprotected file). + Consequently, even though the methods described herein come with + proofs of security, developers must still execute caution when + developing applications that implement these methods. + +5.1 Rekeying Considerations + + Section 3 of this document makes two rekeying recommendations: (1) + rekey at least once every 2**32 packets and (2) rekey after a certain + number of encrypted blocks (eg, 2**(L/4) blocks if the block cipher's + block length L is at least 128 bits). The motivations for + recommendations (1) and (2) are different, and we consider each + recommendation in turn. Briefly, (1) is designed to protect against + information leakage through the SSH protocol's underlying MAC and (2) + is designed to protect against information leakage through the SSH + protocol's underlying encryption scheme. Please note that, depending + on the encryption method's block length L and the number of blocks + encrypted per packet, recommendation (1) may supersede recommendation + (2) or visa-versa. + + Recommendation (1) states that SSH implementations should rekey at + least once every 2**32 packets. As [BKN] show, if more than 2**32 + packets are encrypted and MACed by the SSH Transport Protocol between + rekeyings, then the SSH Transport Protocol's underlying MAC may begin + to leak information about the protocol's payload data. In more + detail, an adversary looks for a collision between the MACs + associated to two packets that were MACed with the same 32-bit + sequence number (see Section 4.4 of [SSH-TRANS]); if a collision is + found, then the payload data associated with those two ciphertexts is + probably identical. Note that this problem occurs regardless of how + secure the underlying encryption method is. Implementors who decide + not to rekey at least once every 2**32 packets should understand this + issue. + + Note that compressing payload data before encrypting and MACing will + not significantly reduce the risk of information leakage through the + underlying MAC. Similarly, the use of random (and unpredictable to + an adversary) padding will not prevent information leakage through + the underlying MAC [BKN]. + + One alternative to recommendation (1) would be to make the SSH + Transport Protocol's sequence number more than 32 bits long. This + + + +Bellare, Kohno, and Namprempre [Page 7] + +Internet Draft Month, Year + + + document does not suggest increasing the length of the sequence + number because doing so could hinder interoperability with older + version of the SSH protocol. Another alternative to recommendation + (1) would be to switch from HMAC to a privacy-preserving randomized + MAC. + + Recommendation (2) states that SSH implementations should rekey + before encrypting more than 2**(L/4) blocks with the same key + (assuming L is at least 128). This recommendation is designed to + minimize the risk of birthday attacks against the encryption method's + underlying block cipher. For example, there is a theoretical privacy + attack against stateful-decryption counter mode if an adversary is + allowed to encrypt approximately 2**(L/2) messages with the same key. + It is because of these birthday attacks that implementors are highly + encouraged to use secure block ciphers with large block lengths. + +5.2 Encryption Method Considerations + + Researchers have recently shown that the original CBC-based + encryption methods in [SSH-TRANS] are vulnerable to chosen-plaintext + privacy attacks [DAI,BKN]. The new stateful-decryption counter mode + encryption methods described in Section 4 of this document were + designed to be secure replacements to the original encryption methods + described in [SSH-TRANS]. + + Many people shy away from counter mode-based encryption schemes + because, when used incorrectly (such as when the keystream is allowed + to repeat), counter mode can be very insecure. Fortunately, the + common concerns with counter mode do not apply to SSH because of the + rekeying recommendations and because of the additional protection + provided by the transport protocol's MAC. This discussion is + formalized with proofs of security in [BKN]. + + As an additional note, when one of the stateful-decryption counter + mode encryption methods (Section 4) is used, then the padding + included in an SSH packet (Section 4 of [SSH-TRANS]) need not be (but + can still be) random. This eliminates the need to generate + cryptographically-secure pseudorandom bytes for each packet. + + One property of counter mode encryption is that it does not require + messages to be padded to a multiple of the block cipher's block + length. Although not padding messages can reduce the protocol's + network consumption, this document requires padding to be a multiple + of the block cipher's block length in order to (1) not alter the + packet description in [SSH-TRANS] and (2) not leak precise + information about the length of the packet's payload data. (Although + there may be some networks savings for padding to only 8-bytes even + if the block cipher uses 16-byte blocks, because of (1) we do not + + + +Bellare, Kohno, and Namprempre [Page 8] + +Internet Draft Month, Year + + + make that recommendation here.) + + In addition to stateful-decryption counter mode, [BKN] describe other + provably-secure encryption methods for use with the SSH Transport + Protocol. The stateful-decryption counter mode methods in Section 4 + are, however, the preferred alternatives to the insecure methods in + [SSH-TRANS] because stateful-decryption counter mode is the most + efficient (both in terms of network consumption and in terms of the + number of required cryptographic operations per packet). + +References + + [AES] Daemon, J. and Rijmen, V., "AES Proposal: Rijndael", + NIST AES Proposal, 1998. + + [BKN] Bellare, M., Kohno, T., and Namprempre, C., + "Authenticated Encryption in SSH: Provably Fixing the + SSH Binary Packet Protocol", Ninth ACM Conference on + Computer and Communications Security, 2002. + + [BN] Bellare, M. and Namprempre, C., "Authenticated + Encryption: Relations among notions and analysis of + the generic composition paradigm", Asiacrypt 2000. + + [DAI] Dai, W., "An Attack Against SSH2 Protocol", Email to + the ietf-ssh@netbsd.org email list, 2002. + + [KRAWCZYK] Krawczyk, H., "The Order of Encryption and + Authentication for Protecting Communications (Or: How + secure is SSL?)", Crypto 2001. + + [RFC2119] Bradner, S., "Key Words for Use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2144] Adams, C., "The CAST-128 Encryption Algorithm", RFC + 2144, May 1997. + + [SCHNEIER] Schneier, B., "Applied Cryptography Second Edition: + Protocols algorithms and source in code in C", Wiley, + 1996. + + [SERPENT] Anderson, R., Biham, E., and Knudsen, L. "Serpent: A + proposal for the Advanced Encryption Standard", NIST + AES Proposal, 1998. + + [SSH-ARCH] Ylonen, T., et. al., "SSH Protocol Architecture", + I-D draft-ietf-architecture-12.txt, January 2002. + + + + +Bellare, Kohno, and Namprempre [Page 9] + +Internet Draft Month, Year + + + [SSH-TRANS] Ylonen, T., et. al., "SSH Transport Layer Protocol", + I-D draft-ietf-transport-14.txt, March 2002. + + [TWOFISH] Schneier, B., et. al., "The Twofish Encryptions + Algorithm: A 128-bit block cipher, 1st Edition", + Wiley, 1999. + +Authors' Addresses: + + Mihir Bellare + Department of Computer Science and Engineering + University of California at San Diego + 9500 Gilman Drive, MC 0114 + La Jolla, CA 92093-0114 + + Phone: +1 858-822-2977 + EMail: mihir@cs.ucsd.edu + + Tadayoshi Kohno + Department of Computer Science and Engineering + University of California at San Diego + 9500 Gilman Drive, MC 0114 + La Jolla, CA 92093-0114 + + Phone: +1 858-822-2977 + EMail: tkohno@cs.ucsd.edu + + Chanathip Namprempre + Thammasat University + Faculty of Engineering + Electrical Engineering Department + Rangsit Campus, Klong Luang + Pathumthani, Thailand 12121 + + EMail: meaw@alum.mit.edu + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + + + +Bellare, Kohno, and Namprempre [Page 10] + +Internet Draft Month, Year + + + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgments + + Mihir Bellare and Chanathip Namprempre were supported by NSF Grant + CCR-0098123, NSF Grant ANR-0129617 and an IBM Faculty Partnership + Development Award. Tadayoshi Kohno was supported by a National + Defense Science and Engineering Fellowship. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Bellare, Kohno, and Namprempre [Page 11] + \ No newline at end of file diff --git a/doc/draft-ietf-secsh-publickeyfile-03.txt b/doc/draft-ietf-secsh-publickeyfile-03.txt new file mode 100644 index 00000000..766f494e --- /dev/null +++ b/doc/draft-ietf-secsh-publickeyfile-03.txt @@ -0,0 +1,506 @@ + + + +Secure Shell Working Group J. Galbraith +Internet-Draft VanDyke Software +Expires: April 16, 2003 R. Thayer + The Tillerman Group + October 16, 2002 + + + SSH Public Key File Format + draft-ietf-secsh-publickeyfile-03.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on April 16, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document formally documents the existing public key file format + in use for exchanging public keys between different SSH + implementations. + + + + + + + + + + +Galbraith & Thayer Expires April 16, 2003 [Page 1] + +Internet-Draft SSH Public Key File Format October 2002 + + +Table of Contents + + 1. Conventions used in this document . . . . . . . . . . . . . 3 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 + 3. Key File Format . . . . . . . . . . . . . . . . . . . . . . 5 + 3.1 Line termination Characters . . . . . . . . . . . . . . . . 5 + 3.2 Begin and end markers . . . . . . . . . . . . . . . . . . . 5 + 3.3 Key File Header . . . . . . . . . . . . . . . . . . . . . . 5 + 3.3.1 Subject Header . . . . . . . . . . . . . . . . . . . . . . . 6 + 3.3.2 Comment Header . . . . . . . . . . . . . . . . . . . . . . . 6 + 3.4 Public Key File Body . . . . . . . . . . . . . . . . . . . . 6 + 3.5 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 7 + References . . . . . . . . . . . . . . . . . . . . . . . . . 8 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 8 + Full Copyright Statement . . . . . . . . . . . . . . . . . . 9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith & Thayer Expires April 16, 2003 [Page 2] + +Internet-Draft SSH Public Key File Format October 2002 + + +1. Conventions used in this document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [4]. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith & Thayer Expires April 16, 2003 [Page 3] + +Internet-Draft SSH Public Key File Format October 2002 + + +2. Introduction + + In order to use public key authentication, public keys must be + exchanged between client and server. This document formally + describes the existing public key file format, with few exceptions. + + Where this document departs from current practice, it also suggests a + mechanism for backwards compatibility. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith & Thayer Expires April 16, 2003 [Page 4] + +Internet-Draft SSH Public Key File Format October 2002 + + +3. Key File Format + + SSH implementations must share public key files between the client + and the server in order interoperate. + + A key file is a text file, containing a sequence of lines. Each line + in the file MUST NOT be longer than 72 bytes. + +3.1 Line termination Characters + + In order to achieve the goal of being able to exchange public key + files between servers, implementations are REQUIRED to read files + using any of the common line termination sequence, , or + . + + Implementations may generate files using which ever line termination + convention is most convenient + +3.2 Begin and end markers + + The first line of a conforming key file MUST be a begin marker, which + is the literal text: + + ---- BEGIN SSH2 PUBLIC KEY ---- + + The last line of a conforming key file MUST be a end marker, which is + the literal text: + + ---- END SSH2 PUBLIC KEY ---- + +3.3 Key File Header + + The key file header section consists of multiple RFC822 - style + header fields. Each field is a line of the following format: + + Header-tag ':' ' ' Header-value + + The Header-tag MUST NOT be more than 64 bytes. The Header-value MUST + NOT be more than 1024 bytes. Each line in the header MUST NOT be + more than 72 bytes. + + A line is continued if the last character in the line is a '\'. If + the last character of a line is a '\', then the logical contents of + the line is formed by removing the '\' and appending the contents of + the next line. + + The Header-tag MUST be US-ASCII. The Header-value MUST be encoded in + UTF-8. [2] + + + +Galbraith & Thayer Expires April 16, 2003 [Page 5] + +Internet-Draft SSH Public Key File Format October 2002 + + + A line that is not a continuation line that has no ':' in it is + assumed to be the first line of the base 64 encoded body (Section 8) + + Compliant implementations MUST ignore unrecognized header fields. + Implementations SHOULD preserve unrecognized header fields when + manipulating the key file. + + Existing implementations may not correctly handle unrecognized + fields. During a transition period, implementations SHOULD generate + key file headers that contain only a Subject field followed by a + Comment field. + +3.3.1 Subject Header + + This field currently is used to store the login-name that the key was + generated under. For example: + + Subject: user + +3.3.2 Comment Header + + Contain a user specified comment which will be displayed when using + the key. + + It is suggested that this field default to user@hostname for the user + and machine used to generate the key. For example: + + Comment: user@mycompany.com + + Currently, common practice is to quote the Header-value of the + Comment, and some existing implementations fail if these quotes are + omitted. + + Compliant implementations MUST function correctly if the quotes are + omitted. + + During an interim period implementations MAY include the quotes. If + the first and last characters of the Header-value are matching + quotes, implementations SHOULD remove them before using the value. + +3.4 Public Key File Body + + The body of a public key file consists of the public key blob as + described in the SSH transport draft [1], section 4.6, "Public Key + Algorithms", encoded in base 64 as specified in RFC-2045, section + 6.8, "Base64 Content-Transfer-Encoding". [5] + + As with all other lines, each line in the body MUST NOT be longer + + + +Galbraith & Thayer Expires April 16, 2003 [Page 6] + +Internet-Draft SSH Public Key File Format October 2002 + + + than 72 characters. + +3.5 Examples + + The following are some example public key files that are compliant: + + ---- BEGIN SSH2 PUBLIC KEY ---- + Comment: "1024-bit RSA, converted from OpenSSH by galb@test1" + AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRbYY + Fw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ5TT4 + SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= + ---- END SSH2 PUBLIC KEY ---- + + + ---- BEGIN SSH2 PUBLIC KEY ---- + Comment: DSA Public Key for use with MyIsp + AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6 + ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14 + Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZ + DPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+N + jB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc + 0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gH + pRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74q + XviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuM + ch5VGPP+CDqzCM4loWgV + ---- END SSH2 PUBLIC KEY ---- + + + ---- BEGIN SSH2 PUBLIC KEY ---- + Subject: galb + Comment: 1024-bit rsa, created by galb@shimi Mon Jan 15 08:31:24 2001 + AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt459 + 6k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6 + NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0= + ---- END SSH2 PUBLIC KEY ---- + + + + + + + + + + + + + + + + +Galbraith & Thayer Expires April 16, 2003 [Page 7] + +Internet-Draft SSH Public Key File Format October 2002 + + +References + + [1] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Transport Protocol", September 2002. + + [2] Yergeau, F., "UTF-8, a Transformation Format of Unicode and ISO + 10646", October 1996. + + [3] Bradner, S., "The Internet Standards Process -- Revision 3", + October 1996. + + [4] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", March 1997. + + [5] Freed and Borenstein, "Multipurpose Internet Mail Extensions + (MIME) Part One: Format of Internet Message Bodies", November + 1996. + + +Authors' Addresses + + Joseph Galbraith + VanDyke Software + 4848 Tramway Ridge Blvd + Suite 101 + Albuquerque, NM 87111 + US + + Phone: +1 505 332 5700 + EMail: galb-list@vandyke.com + + + Rodney Thayer + The Tillerman Group + 370 Altair Way, PMB 321 + Sunnyvale, CA 94086 + + Phone: +1 408 757 9693 + EMail: rodney@tillerman.to + + + + + + + + + + + + +Galbraith & Thayer Expires April 16, 2003 [Page 8] + +Internet-Draft SSH Public Key File Format October 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Galbraith & Thayer Expires April 16, 2003 [Page 9] + + diff --git a/doc/draft-ietf-secsh-scp-sftp-ssh-uri-00.txt b/doc/draft-ietf-secsh-scp-sftp-ssh-uri-00.txt new file mode 100644 index 00000000..f582a49b --- /dev/null +++ b/doc/draft-ietf-secsh-scp-sftp-ssh-uri-00.txt @@ -0,0 +1,426 @@ +Network Working Group S. Suehring +Internet-Draft Sentry Insurance +Expires February 8, 2004 J. Salowey + Cisco Systems + August 8, 2003 + + + SCP/SFTP/SSH URI Format + draft-ietf-secsh-scp-sftp-ssh-uri-00.txt + +Status of this Memo + + This document is an Internet-Draft and is subject to all provisions + of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/1id-abstracts.html + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html + + This Internet Draft will expire on February 8, 2004. + + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + +Abstract + + This document describes the Uniform Resource Identifiers used to + locate resources for the SCP, SFTP, and SSH protocols. The document + describes the generic syntax involved in URI definitions as well as + specific definitions for each protocol. These specific definitions + may include user credentials such as username and password and also + may include other parameters such as fingerprint. In addition, + security considerations and examples are also provided within this + document. + + +General Syntax + + The URI for each protocol shall consist of the scheme and the scheme + specific portion separated by a colon ":", as discussed in RFC 2396 + [1]. This specification shall adopt the definitions "port", "host", + "scheme", "userinfo", and "authority" from RFC 2396. + + +Suehring & Salowey Expires February 8, 2004 [Page 1] + +Internet Draft SCP/SFTP/SSH URI Format August 8, 2003 + +SSH URI + + The SSH scheme shall consist of the protocol acronym followed by a + colon ":" and a double slash "//" in accordance with RFC 2718 [2]. + + The first component of the scheme specific portion MAY include + credentials (userinfo) consisting of a username and optionally also + including a password. Including the password in the URL is NOT + RECOMMENDED. The username and password components are separated by + a single colon ":". + + Following the userinfo, if present, the at-sign "@" shall + precede the authority section of the URI. Optionally, the + authority section MAY also include the port preceded by a colon ":". + If the port is not included, port 22 is assumed. Following the port + additional parameters may be specified. These parameters are + defined in the connection parameters section. + + ssh_URI = "ssh://" [ userinfo "@" ] host [ ":" port ] + [;conn-parameter=value] + +SCP and SFTP URI + + For SCP and SFTP, the scheme portion (scp: or sftp:) is followed by + a double slash "//". + + Both SCP and SFTP URLs are terminated by a single slash "/" followed + by the path information to the requested resource. + + The first component of the scheme specific portion MAY include + credentials (userinfo) consisting of a username and optionally also + including a password. Including the password in the URL is NOT + RECOMMENDED. The username and password components are separated by + a single colon ":". + + Following the userinfo, if present, the at-sign "@" shall precede + the authority section of the URL. Optionally, the authority section + MAY also include the port preceded by a colon ":". If the port is + not included, port 22 is assumed. Following the port additional + parameters may be specified. These parameters are defined in the + connection parameters section. + + scp_URI = "scp://" [ userinfo "@" ] host [ ":" port ] + [ ; parameter = value ] [ abs_path ] + + Following the port additional parameters may be specified. These + parameters are defined in the connection parameters section. + Following the path additional sftp specific parameters may be + specified. + + sftp_URI = "sftp://" [ userinfo "@" ] host [ ":" port ] + [;conn-parameter=value] [ abs_path ] [;sftp-parameter=value] + + + +Suehring & Salowey Expires February 8, 2004 [Page 2] + +Internet Draft SCP/SFTP/SSH URI Format August 8, 2003 + + +Parameters + +SSH connection parameters + + The following parameters are associated with an SSH connection and + are applicable to SSH, SFTP and SCP. All parameters are optional + and MUST NOT overwrite configured defaults. Individual parameters + are separated by a comma (","). + +fingerprint + + The fingerprint parameter contains the fingerprint of the host key + for the host specified in the URL. The fingerprint is encoded as + in [3]. This parameter MUST NOT overwrite a key that is already + configured for the host. They fingerprint MAY be used to validate + the authenticity of the host key if the URL was obtained from an + authenticated source with its integrity protected. If this + parameter is not included then the validity of the host key is + validated using another method. See Security Considerations section + for additional considerations. There MUST be only one fingerprint + parameter for a given URL. + +cipher + + The cipher parameter indicates an acceptable encryption mechanism to + use in making the connection. The value is the string specifying the + SSH cipher type. This parameter MUST NOT add a mechanism to a + configured list of default configured acceptable encryption types. + If this parameter is not specified then the default configured cipher + list is used. There may be more than one cipher parameter. + +integrity + + The integrity parameter indicates an acceptable data integrity + mechanism to use in making the connection. The value is the string + specifying the SSH data integrity type. This parameter MUST NOT add + a mechanism to a configured list of default configured acceptable + data integrity types. If this parameter is not specified then the + default configured data integrity list is used. There may be more + than one integrity parameter. + +key-xchg + + The key-xchg parameter indicates an acceptable key exchange mechanism + to use when making the connection. The value is the string + specifying the SSH key exchange type. This parameter MUST NOT add a + mechanism to a configured list of default configured acceptable key + exchange types. If this parameter is not specified then the default + configured key exchange list is used. There may be more than one + key-xchg parameter. + + + + + +Suehring & Salowey Expires February 8, 2004 [Page 3] + +Internet Draft SCP/SFTP/SSH URI Format August 8, 2003 + +host-key-alg + + The host-key-alg parameter indicates an host key to use when making + the connection. The value is the string specifying the SSH host key + type. This parameter MUST NOT add a mechanism to a configured list + of default configured acceptable host key types. If this parameter + is not specified then the default configured host key type list is + used. There may be more than one host-key-alg parameter. + +user-auth + + The user-auth parameter indicates a user authentication mechanism to + use when making the connection. The value is the string specifying + the SSH user authentication mechanism type. This parameter MUST NOT + add a mechanism to a configured list of default configured + acceptable user authentication mechanism types. If this parameter + is not specified then the default configured user authentication + mechanism type list is used. There may be more than one user-auth + parameter. + +SFTP Parameters + + The SFTP parameters determine how to handle the file transfer + character translation. + +newline + + The newline parameter determines how the server translates new line + indicators. The possible choices are usually "\r" or "\n" or "\r\n". + The default is "\r\n". + +typecode + + The typecode identifies the type of file which determines how it + will be treated. Possible values are "i" for binary files, "a" for + text files, and "d" for directory listings. + + +Examples + + The following section shows basic examples of URLs for each + protocol. This section should not be considered to include all + possible combinations of URLs for each protocol. + + ssh://user@host + + ssh://user@host:2222 + + ssh://joeuser@example.com;fingerprint=c1:b1:30:29:d7:b8:de:6c + :97:77:10:d7:46:41:63:87,cipher=aes-cbc + + scp://user:password@host/file.txt + + sftp://user@host/dir/path/file.txt + + +Suehring & Salowey Expires February 8, 2004 [Page 4] + +Internet Draft SCP/SFTP/SSH URI Format August 8, 2003 + + sftp://joeuser@example.com:2222;fingerprint=c1:b1:30:29:d7:b8 + :de:6c:97:77:10:d7:46:41:63:87,cipher= + aes-cbc/pub/docs/test.txt;typecode=a + + +Security Considerations + + In general, URIs themselves have no security considerations. + However, since the password for each scheme can optionally be + included within the URL it should be noted that doing so poses a + security risk. Since URLs are usually sent in the clear with no + encryption or other security, any password or other credentials + (userinfo) included could be seen by a potential attacker. + + The fingerprint should only be used to validate the host key only if + the URL can be determined to be authentic from a trusted entity. + For example, the URL may be received through secure email or HTTPS + from a trusted and verifiable source. It is possible that the SSH + implementation may not be able to determine if the URL is authentic + in which case it SHOULD prompt the user to either allow or disallow + the connection based on the information provided. The SSH + implementation MUST NOT overwrite a currently configured public key + based on the URL alone. + + The other connection parameters MUST NOT add any mechanism to the + list of configured acceptable mechanisms defined in the SSH client. + +Normative References + + [1] Berners-Lee, T., Fielding, R., Masinter, L., "Uniform Resource + Identifiers (URI): Generic Syntax", RFC 2396, August 1998. + + [2] Masinter, L., et. al., "Guidelines for new URL Schemes", RFC + 2718, November 1999. + + [3] Markus Friedl, "SSH Fingerprint Format", + http://www.ietf.org/internet-drafts/ + draft-ietf-secsh-fingerprint-01.txt, + work in progress + +Non-Normative References + + Mealling, M., Denenberg, R., "Report from the Joint W3C/IETF URI + Planning Interest Group: Uniform Resource Identifiers (URIs), URLs, + and Uniform Resource Names (URNs): Clarifications and + Recommendations", RFC 3305, August 2002. + + +Author Information + + Steve Suehring + Sentry Insurance + 1800 North Point Dr, G2/61-17 + Stevens Point, WI 54481 + suehring@braingia.com + + Joseph Salowey + Cisco Systems + 2901 Third Avenue + Seattle, WA 98121 + E-mail: jsalowey@cisco.com + + +Suehring & Salowey Expires February 8, 2004 [Page 5] + +Internet Draft SCP/SFTP/SSH URI Format August 8, 2003 + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + + + + + +Suehring & Salowey Expires February 8, 2004 [Page 6] + +Internet Draft SCP/SFTP/SSH URI Format August 8, 2003 + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Suehring & Salowey Expires February 8, 2004 [Page 7] diff --git a/doc/draft-ietf-secsh-transport-16.txt b/doc/draft-ietf-secsh-transport-16.txt new file mode 100644 index 00000000..b4564f17 --- /dev/null +++ b/doc/draft-ietf-secsh-transport-16.txt @@ -0,0 +1,1624 @@ + + +Network Working Group T. Ylonen +Internet-Draft T. Kivinen +Expires: January 12, 2004 SSH Communications Security Corp + M. Saarinen + University of Jyvaskyla + T. Rinne + S. Lehtinen + SSH Communications Security Corp + July 14, 2003 + + + SSH Transport Layer Protocol + draft-ietf-secsh-transport-16.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on January 12, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. + + This document describes the SSH transport layer protocol which + typically runs on top of TCP/IP. The protocol can be used as a + + + +Ylonen, et. al. Expires January 12, 2004 [Page 1] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + basis for a number of secure network services. It provides strong + encryption, server authentication, and integrity protection. It + may also provide compression. + + Key exchange method, public key algorithm, symmetric encryption + algorithm, message authentication algorithm, and hash algorithm + are all negotiated. + + This document also describes the Diffie-Hellman key exchange + method and the minimal set of algorithms that are needed to + implement the SSH transport layer protocol. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 4 + 3. Connection Setup . . . . . . . . . . . . . . . . . . . . . . . 4 + 3.1 Use over TCP/IP . . . . . . . . . . . . . . . . . . . . . . . 4 + 3.2 Protocol Version Exchange . . . . . . . . . . . . . . . . . . 4 + 3.3 Compatibility With Old SSH Versions . . . . . . . . . . . . . 5 + 3.4 Old Client, New Server . . . . . . . . . . . . . . . . . . . . 5 + 3.5 New Client, Old Server . . . . . . . . . . . . . . . . . . . . 6 + 4. Binary Packet Protocol . . . . . . . . . . . . . . . . . . . . 6 + 4.1 Maximum Packet Length . . . . . . . . . . . . . . . . . . . . 7 + 4.2 Compression . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 4.3 Encryption . . . . . . . . . . . . . . . . . . . . . . . . . . 8 + 4.4 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . . 10 + 4.5 Key Exchange Methods . . . . . . . . . . . . . . . . . . . . . 11 + 4.6 Public Key Algorithms . . . . . . . . . . . . . . . . . . . . 11 + 5. Key Exchange . . . . . . . . . . . . . . . . . . . . . . . . . 14 + 5.1 Algorithm Negotiation . . . . . . . . . . . . . . . . . . . . 14 + 5.2 Output from Key Exchange . . . . . . . . . . . . . . . . . . . 17 + 5.3 Taking Keys Into Use . . . . . . . . . . . . . . . . . . . . . 18 + 6. Diffie-Hellman Key Exchange . . . . . . . . . . . . . . . . . 19 + 6.1 diffie-hellman-group1-sha1 . . . . . . . . . . . . . . . . . . 20 + 7. Key Re-Exchange . . . . . . . . . . . . . . . . . . . . . . . 21 + 8. Service Request . . . . . . . . . . . . . . . . . . . . . . . 22 + 9. Additional Messages . . . . . . . . . . . . . . . . . . . . . 22 + 9.1 Disconnection Message . . . . . . . . . . . . . . . . . . . . 23 + 9.2 Ignored Data Message . . . . . . . . . . . . . . . . . . . . . 23 + 9.3 Debug Message . . . . . . . . . . . . . . . . . . . . . . . . 24 + 9.4 Reserved Messages . . . . . . . . . . . . . . . . . . . . . . 24 + 10. Summary of Message Numbers . . . . . . . . . . . . . . . . . . 24 + 11. Security Considerations . . . . . . . . . . . . . . . . . . . 25 + 12. Intellectual Property . . . . . . . . . . . . . . . . . . . . 25 + 13. Additional Information . . . . . . . . . . . . . . . . . . . . 25 + References . . . . . . . . . . . . . . . . . . . . . . . . . . 26 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 27 + + + +Ylonen, et. al. Expires January 12, 2004 [Page 2] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + Full Copyright Statement . . . . . . . . . . . . . . . . . . . 29 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 3] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + 1. Introduction + + The SSH transport layer is a secure low level transport protocol. + It provides strong encryption, cryptographic host authentication, + and integrity protection. + + Authentication in this protocol level is host-based; this protocol + does not perform user authentication. A higher level protocol for + user authentication can be designed on top of this protocol. + + The protocol has been designed to be simple, flexible, to allow + parameter negotiation, and to minimize the number of round-trips. + Key exchange method, public key algorithm, symmetric encryption + algorithm, message authentication algorithm, and hash algorithm + are all negotiated. It is expected that in most environments, + only 2 round-trips will be needed for full key exchange, server + authentication, service request, and acceptance notification of + service request. The worst case is 3 round-trips. + + 2. Conventions Used in This Document + + The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD + NOT", and "MAY" that appear in this document are to be interpreted + as described in [RFC2119] + + The used data types and terminology are specified in the + architecture document [SSH-ARCH] + + The architecture document also discusses the algorithm naming + conventions that MUST be used with the SSH protocols. + + 3. Connection Setup + + SSH works over any 8-bit clean, binary-transparent transport. The + underlying transport SHOULD protect against transmission errors as + such errors cause the SSH connection to terminate. + + The client initiates the connection. + + 3.1 Use over TCP/IP + + When used over TCP/IP, the server normally listens for connections + on port 22. This port number has been registered with the IANA, + and has been officially assigned for SSH. + + 3.2 Protocol Version Exchange + + When the connection has been established, both sides MUST send an + + + +Ylonen, et. al. Expires January 12, 2004 [Page 4] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + identification string of the form "SSH-protoversion- + softwareversion comments", followed by carriage return and newline + characters (ASCII 13 and 10, respectively). Both sides MUST be + able to process identification strings without carriage return + character. No null character is sent. The maximum length of the + string is 255 characters, including the carriage return and + newline. + + The part of the identification string preceding carriage return + and newline is used in the Diffie-Hellman key exchange (see + Section Section 6). + + The server MAY send other lines of data before sending the version + string. Each line SHOULD be terminated by a carriage return and + newline. Such lines MUST NOT begin with "SSH-", and SHOULD be + encoded in ISO-10646 UTF-8 [RFC2279] (language is not specified). + Clients MUST be able to process such lines; they MAY be silently + ignored, or MAY be displayed to the client user; if they are + displayed, control character filtering discussed in [SSH-ARCH] + SHOULD be used. The primary use of this feature is to allow TCP- + wrappers to display an error message before disconnecting. + + Version strings MUST consist of printable US-ASCII characters, not + including whitespaces or a minus sign (-). The version string is + primarily used to trigger compatibility extensions and to indicate + the capabilities of an implementation. The comment string should + contain additional information that might be useful in solving + user problems. + + The protocol version described in this document is 2.0. + + Key exchange will begin immediately after sending this identifier. + All packets following the identification string SHALL use the + binary packet protocol, to be described below. + + 3.3 Compatibility With Old SSH Versions + + During the transition period, it is important to be able to work + in a way that is compatible with the installed SSH clients and + servers that use an older version of the protocol. Information in + this section is only relevant for implementations supporting + compatibility with SSH versions 1.x. + + 3.4 Old Client, New Server + + Server implementations MAY support a configurable "compatibility" + flag that enables compatibility with old versions. When this flag + is on, the server SHOULD identify its protocol version as "1.99". + + + +Ylonen, et. al. Expires January 12, 2004 [Page 5] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + Clients using protocol 2.0 MUST be able to identify this as + identical to "2.0". In this mode the server SHOULD NOT send the + carriage return character (ASCII 13) after the version + identification string. + + In the compatibility mode the server SHOULD NOT send any further + data after its initialization string until it has received an + identification string from the client. The server can then + determine whether the client is using an old protocol, and can + revert to the old protocol if required. In the compatibility + mode, the server MUST NOT send additional data before the version + string. + + When compatibility with old clients is not needed, the server MAY + send its initial key exchange data immediately after the + identification string. + + 3.5 New Client, Old Server + + Since the new client MAY immediately send additional data after + its identification string (before receiving server's + identification), the old protocol may already have been corrupted + when the client learns that the server is old. When this happens, + the client SHOULD close the connection to the server, and + reconnect using the old protocol. + + 4. Binary Packet Protocol + + Each packet is in the following format: + + uint32 packet_length + byte padding_length + byte[n1] payload; n1 = packet_length - padding_length - 1 + byte[n2] random padding; n2 = padding_length + byte[m] mac (message authentication code); m = mac_length + + packet_length + The length of the packet (bytes), not including MAC or the + packet_length field itself. + + padding_length + Length of padding (bytes). + + payload + The useful contents of the packet. If compression has been + negotiated, this field is compressed. Initially, + compression MUST be "none". + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 6] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + random padding + Arbitrary-length padding, such that the total length of + (packet_length || padding_length || payload || padding) is a + multiple of the cipher block size or 8, whichever is larger. + There MUST be at least four bytes of padding. The padding + SHOULD consist of random bytes. The maximum amount of + padding is 255 bytes. + + mac + Message authentication code. If message authentication has + been negotiated, this field contains the MAC bytes. + Initially, the MAC algorithm MUST be "none". + + + Note that length of the concatenation of packet length, padding + length, payload, and padding MUST be a multiple of the cipher + block size or 8, whichever is larger. This constraint MUST be + enforced even when using stream ciphers. Note that the packet + length field is also encrypted, and processing it requires special + care when sending or receiving packets. + + The minimum size of a packet is 16 (or the cipher block size, + whichever is larger) bytes (plus MAC); implementations SHOULD + decrypt the length after receiving the first 8 (or cipher block + size, whichever is larger) bytes of a packet. + + 4.1 Maximum Packet Length + + All implementations MUST be able to process packets with + uncompressed payload length of 32768 bytes or less and total + packet size of 35000 bytes or less (including length, padding + length, payload, padding, and MAC.). The maximum of 35000 bytes + is an arbitrary chosen value larger than uncompressed size. + Implementations SHOULD support longer packets, where they might be + needed, e.g. if an implementation wants to send a very large + number of certificates. Such packets MAY be sent if the version + string indicates that the other party is able to process them. + However, implementations SHOULD check that the packet length is + reasonable for the implementation to avoid denial-of-service + and/or buffer overflow attacks. + + 4.2 Compression + + If compression has been negotiated, the payload field (and only + it) will be compressed using the negotiated algorithm. The length + field and MAC will be computed from the compressed payload. + Encryption will be done after compression. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 7] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + Compression MAY be stateful, depending on the method. Compression + MUST be independent for each direction, and implementations MUST + allow independently choosing the algorithm for each direction. + + The following compression methods are currently defined: + + none REQUIRED no compression + zlib OPTIONAL ZLIB (LZ77) compression + + The "zlib" compression is described in [RFC1950] and in [RFC1951]. + The compression context is initialized after each key exchange, + and is passed from one packet to the next with only a partial + flush being performed at the end of each packet. A partial flush + means that the current compressed block is ended and all data will + be output. If the current block is not a stored block, one or + more empty blocks are added after the current block to ensure that + there are at least 8 bits counting from the start of the end-of- + block code of the current block to the end of the packet payload. + + Additional methods may be defined as specified in [SSH-ARCH]. + + 4.3 Encryption + + An encryption algorithm and a key will be negotiated during the + key exchange. When encryption is in effect, the packet length, + padding length, payload and padding fields of each packet MUST be + encrypted with the given algorithm. + + The encrypted data in all packets sent in one direction SHOULD be + considered a single data stream. For example, initialization + vectors SHOULD be passed from the end of one packet to the + beginning of the next packet. All ciphers SHOULD use keys with an + effective key length of 128 bits or more. + + The ciphers in each direction MUST run independently of each + other, and implementations MUST allow independently choosing the + algorithm for each direction (if multiple algorithms are allowed + by local policy). + + The following ciphers are currently defined: + + 3des-cbc REQUIRED three-key 3DES in CBC mode + blowfish-cbc RECOMMENDED Blowfish in CBC mode + twofish256-cbc OPTIONAL Twofish in CBC mode, + with 256-bit key + twofish-cbc OPTIONAL alias for "twofish256-cbc" (this + is being retained for + historical reasons) + + + +Ylonen, et. al. Expires January 12, 2004 [Page 8] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + twofish192-cbc OPTIONAL Twofish with 192-bit key + twofish128-cbc RECOMMENDED Twofish with 128-bit key + aes256-cbc OPTIONAL AES (Rijndael) in CBC mode, + with 256-bit key + aes192-cbc OPTIONAL AES with 192-bit key + aes128-cbc RECOMMENDED AES with 128-bit key + serpent256-cbc OPTIONAL Serpent in CBC mode, with + 256-bit key + serpent192-cbc OPTIONAL Serpent with 192-bit key + serpent128-cbc OPTIONAL Serpent with 128-bit key + arcfour OPTIONAL the ARCFOUR stream cipher + idea-cbc OPTIONAL IDEA in CBC mode + cast128-cbc OPTIONAL CAST-128 in CBC mode + none OPTIONAL no encryption; NOT RECOMMENDED + + The "3des-cbc" cipher is three-key triple-DES (encrypt-decrypt- + encrypt), where the first 8 bytes of the key are used for the + first encryption, the next 8 bytes for the decryption, and the + following 8 bytes for the final encryption. This requires 24 + bytes of key data (of which 168 bits are actually used). To + implement CBC mode, outer chaining MUST be used (i.e., there is + only one initialization vector). This is a block cipher with 8 + byte blocks. This algorithm is defined in [SCHNEIER] + + The "blowfish-cbc" cipher is Blowfish in CBC mode, with 128 bit + keys [SCHNEIER]. This is a block cipher with 8 byte blocks. + + The "twofish-cbc" or "twofish256-cbc" cipher is Twofish in CBC + mode, with 256 bit keys as described [TWOFISH]. This is a block + cipher with 16 byte blocks. + + The "twofish192-cbc" cipher. Same as above but with 192-bit key. + + The "twofish128-cbc" cipher. Same as above but with 128-bit key. + + The "aes256-cbc" cipher is AES (Advanced Encryption Standard), + formerly Rijndael, in CBC mode. This version uses 256-bit key. + + The "aes192-cbc" cipher. Same as above but with 192-bit key. + + The "aes128-cbc" cipher. Same as above but with 128-bit key. + + The "serpent256-cbc" cipher in CBC mode, with 256-bit key as + described in the Serpent AES submission. + + The "serpent192-cbc" cipher. Same as above but with 192-bit key. + + The "serpent128-cbc" cipher. Same as above but with 128-bit key. + + + +Ylonen, et. al. Expires January 12, 2004 [Page 9] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + The "arcfour" is the Arcfour stream cipher with 128 bit keys. The + Arcfour cipher is believed to be compatible with the RC4 cipher + [SCHNEIER]. RC4 is a registered trademark of RSA Data Security + Inc. Arcfour (and RC4) has problems with weak keys, and should be + used with caution. + + The "idea-cbc" cipher is the IDEA cipher in CBC mode [SCHNEIER]. + IDEA is patented by Ascom AG. + + The "cast128-cbc" cipher is the CAST-128 cipher in CBC mode + [RFC2144]. + + The "none" algorithm specifies that no encryption is to be done. + Note that this method provides no confidentiality protection, and + it is not recommended. Some functionality (e.g. password + authentication) may be disabled for security reasons if this + cipher is chosen. + + Additional methods may be defined as specified in [SSH-ARCH]. + + 4.4 Data Integrity + + Data integrity is protected by including with each packet a + message authentication code (MAC) that is computed from a shared + secret, packet sequence number, and the contents of the packet. + + The message authentication algorithm and key are negotiated during + key exchange. Initially, no MAC will be in effect, and its length + MUST be zero. After key exchange, the selected MAC will be + computed before encryption from the concatenation of packet data: + + mac = MAC(key, sequence_number || unencrypted_packet) + + where unencrypted_packet is the entire packet without MAC (the + length fields, payload and padding), and sequence_number is an + implicit packet sequence number represented as uint32. The + sequence number is initialized to zero for the first packet, and + is incremented after every packet (regardless of whether + encryption or MAC is in use). It is never reset, even if + keys/algorithms are renegotiated later. It wraps around to zero + after every 2^32 packets. The packet sequence number itself is + not included in the packet sent over the wire. + + The MAC algorithms for each direction MUST run independently, and + implementations MUST allow choosing the algorithm independently + for both directions. + + The MAC bytes resulting from the MAC algorithm MUST be transmitted + + + +Ylonen, et. al. Expires January 12, 2004 [Page 10] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + without encryption as the last part of the packet. The number of + MAC bytes depends on the algorithm chosen. + + The following MAC algorithms are currently defined: + + hmac-sha1 REQUIRED HMAC-SHA1 (digest length = key + length = 20) + hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 (digest + length = 12, key length = 20) + hmac-md5 OPTIONAL HMAC-MD5 (digest length = key + length = 16) + hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 (digest + length = 12, key length = 16) + none OPTIONAL no MAC; NOT RECOMMENDED + + The "hmac-*" algorithms are described in [RFC2104] The "*-n" MACs + use only the first n bits of the resulting value. + + The hash algorithms are described in [SCHNEIER]. + + Additional methods may be defined as specified in [SSH-ARCH]. + + 4.5 Key Exchange Methods + + The key exchange method specifies how one-time session keys are + generated for encryption and for authentication, and how the + server authentication is done. + + Only one REQUIRED key exchange method has been defined: + + diffie-hellman-group1-sha1 REQUIRED + + This method is described later in this document. + + Additional methods may be defined as specified in [SSH-ARCH]. + + 4.6 Public Key Algorithms + + This protocol has been designed to be able to operate with almost + any public key format, encoding, and algorithm (signature and/or + encryption). + + There are several aspects that define a public key type: + o Key format: how is the key encoded and how are certificates + represented. The key blobs in this protocol MAY contain + certificates in addition to keys. + o Signature and/or encryption algorithms. Some key types may not + support both signing and encryption. Key usage may also be + + + +Ylonen, et. al. Expires January 12, 2004 [Page 11] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + restricted by policy statements in e.g. certificates. In this + case, different key types SHOULD be defined for the different + policy alternatives. + o Encoding of signatures and/or encrypted data. This includes + but is not limited to padding, byte order, and data formats. + + The following public key and/or certificate formats are currently defined: + + ssh-dss REQUIRED sign Simple DSS + ssh-rsa RECOMMENDED sign Simple RSA + x509v3-sign-rsa OPTIONAL sign X.509 certificates (RSA key) + x509v3-sign-dss OPTIONAL sign X.509 certificates (DSS key) + spki-sign-rsa OPTIONAL sign SPKI certificates (RSA key) + spki-sign-dss OPTIONAL sign SPKI certificates (DSS key) + pgp-sign-rsa OPTIONAL sign OpenPGP certificates (RSA key) + pgp-sign-dss OPTIONAL sign OpenPGP certificates (DSS key) + + Additional key types may be defined as specified in [SSH-ARCH]. + + The key type MUST always be explicitly known (from algorithm + negotiation or some other source). It is not normally included in + the key blob. + + Certificates and public keys are encoded as follows: + + string certificate or public key format identifier + byte[n] key/certificate data + + The certificate part may have be a zero length string, but a + public key is required. This is the public key that will be used + for authentication; the certificate sequence contained in the + certificate blob can be used to provide authorization. + + Public key / certifcate formats that do not explicitly specify a + signature format identifier MUST use the public key / certificate + format identifier as the signature identifier. + + Signatures are encoded as follows: + string signature format identifier (as specified by the + public key / cert format) + byte[n] signature blob in format specific encoding. + + + The "ssh-dss" key format has the following specific encoding: + + string "ssh-dss" + mpint p + mpint q + + + +Ylonen, et. al. Expires January 12, 2004 [Page 12] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + mpint g + mpint y + + Here the p, q, g, and y parameters form the signature key blob. + + Signing and verifying using this key format is done according to + the Digital Signature Standard [FIPS-186] using the SHA-1 hash. A + description can also be found in [SCHNEIER]. + + The resulting signature is encoded as follows: + + string "ssh-dss" + string dss_signature_blob + + dss_signature_blob is encoded as a string containing r followed by + s (which are 160 bits long integers, without lengths or padding, + unsigned and in network byte order). + + The "ssh-rsa" key format has the following specific encoding: + + string "ssh-rsa" + mpint e + mpint n + + Here the e and n parameters form the signature key blob. + + Signing and verifying using this key format is done according to + [SCHNEIER] and [PKCS1] using the SHA-1 hash. + + The resulting signature is encoded as follows: + + string "ssh-rsa" + string rsa_signature_blob + + rsa_signature_blob is encoded as a string containing s (which is + an integer, without lengths or padding, unsigned and in network + byte order). + + The "spki-sign-rsa" method indicates that the certificate blob + contains a sequence of SPKI certificates. The format of SPKI + certificates is described in [RFC2693]. This method indicates + that the key (or one of the keys in the certificate) is an RSA- + key. + + The "spki-sign-dss". As above, but indicates that the key (or one + of the keys in the certificate) is a DSS-key. + + The "pgp-sign-rsa" method indicates the certificates, the public + + + +Ylonen, et. al. Expires January 12, 2004 [Page 13] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + key, and the signature are in OpenPGP compatible binary format + ([RFC2440]). This method indicates that the key is an RSA-key. + + The "pgp-sign-dss". As above, but indicates that the key is a + DSS-key. + + 5. Key Exchange + + Key exchange begins by each side sending lists of supported + algorithms. Each side has a preferred algorithm in each category, + and it is assumed that most implementations at any given time will + use the same preferred algorithm. Each side MAY guess which + algorithm the other side is using, and MAY send an initial key + exchange packet according to the algorithm if appropriate for the + preferred method. + + Guess is considered wrong, if: + o the kex algorithm and/or the host key algorithm is guessed + wrong (server and client have different preferred algorithm), + or + o if any of the other algorithms cannot be agreed upon (the + procedure is defined below in Section Section 5.1). + + Otherwise, the guess is considered to be right and the + optimistically sent packet MUST be handled as the first key + exchange packet. + + However, if the guess was wrong, and a packet was optimistically + sent by one or both parties, such packets MUST be ignored (even if + the error in the guess would not affect the contents of the + initial packet(s)), and the appropriate side MUST send the correct + initial packet. + + Server authentication in the key exchange MAY be implicit. After + a key exchange with implicit server authentication, the client + MUST wait for response to its service request message before + sending any further data. + + 5.1 Algorithm Negotiation + + Key exchange begins by each side sending the following packet: + + byte SSH_MSG_KEXINIT + byte[16] cookie (random bytes) + string kex_algorithms + string server_host_key_algorithms + string encryption_algorithms_client_to_server + string encryption_algorithms_server_to_client + + + +Ylonen, et. al. Expires January 12, 2004 [Page 14] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + string mac_algorithms_client_to_server + string mac_algorithms_server_to_client + string compression_algorithms_client_to_server + string compression_algorithms_server_to_client + string languages_client_to_server + string languages_server_to_client + boolean first_kex_packet_follows + uint32 0 (reserved for future extension) + + Each of the algorithm strings MUST be a comma-separated list of + algorithm names (see ''Algorithm Naming'' in [SSH-ARCH]). Each + supported (allowed) algorithm MUST be listed in order of + preference. + + The first algorithm in each list MUST be the preferred (guessed) + algorithm. Each string MUST contain at least one algorithm name. + + + cookie + The cookie MUST be a random value generated by the sender. + Its purpose is to make it impossible for either side to + fully determine the keys and the session identifier. + + kex_algorithms + Key exchange algorithms were defined above. The first + algorithm MUST be the preferred (and guessed) algorithm. If + both sides make the same guess, that algorithm MUST be used. + Otherwise, the following algorithm MUST be used to choose a + key exchange method: iterate over client's kex algorithms, + one at a time. Choose the first algorithm that satisfies + the following conditions: + + the server also supports the algorithm, + + if the algorithm requires an encryption-capable host key, + there is an encryption-capable algorithm on the server's + server_host_key_algorithms that is also supported by the + client, and + + if the algorithm requires a signature-capable host key, + there is a signature-capable algorithm on the server's + server_host_key_algorithms that is also supported by the + client. + + If no algorithm satisfying all these conditions can be + found, the connection fails, and both sides MUST + disconnect. + + server_host_key_algorithms + List of the algorithms supported for the server host key. + The server lists the algorithms for which it has host keys; + the client lists the algorithms that it is willing to + + + +Ylonen, et. al. Expires January 12, 2004 [Page 15] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + accept. (There MAY be multiple host keys for a host, + possibly with different algorithms.) + + Some host keys may not support both signatures and + encryption (this can be determined from the algorithm), and + thus not all host keys are valid for all key exchange + methods. + + Algorithm selection depends on whether the chosen key + exchange algorithm requires a signature or encryption + capable host key. It MUST be possible to determine this + from the public key algorithm name. The first algorithm on + the client's list that satisfies the requirements and is + also supported by the server MUST be chosen. If there is no + such algorithm, both sides MUST disconnect. + + encryption_algorithms + Lists the acceptable symmetric encryption algorithms in + order of preference. The chosen encryption algorithm to + each direction MUST be the first algorithm on the client's + list that is also on the server's list. If there is no such + algorithm, both sides MUST disconnect. + + Note that "none" must be explicitly listed if it is to be + acceptable. The defined algorithm names are listed in + Section Section 4.3. + + mac_algorithms + Lists the acceptable MAC algorithms in order of preference. + The chosen MAC algorithm MUST be the first algorithm on the + client's list that is also on the server's list. If there + is no such algorithm, both sides MUST disconnect. + + Note that "none" must be explicitly listed if it is to be + acceptable. The MAC algorithm names are listed in Section + Figure 1. + + compression_algorithms + Lists the acceptable compression algorithms in order of + preference. The chosen compression algorithm MUST be the + first algorithm on the client's list that is also on the + server's list. If there is no such algorithm, both sides + MUST disconnect. + + Note that "none" must be explicitly listed if it is to be + acceptable. The compression algorithm names are listed in + Section Section 4.2. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 16] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + languages + This is a comma-separated list of language tags in order of + preference [RFC1766]. Both parties MAY ignore this list. + If there are no language preferences, this list SHOULD be + empty. + + first_kex_packet_follows + Indicates whether a guessed key exchange packet follows. If + a guessed packet will be sent, this MUST be TRUE. If no + guessed packet will be sent, this MUST be FALSE. + + After receiving the SSH_MSG_KEXINIT packet from the other + side, each party will know whether their guess was right. + If the other party's guess was wrong, and this field was + TRUE, the next packet MUST be silently ignored, and both + sides MUST then act as determined by the negotiated key + exchange method. If the guess was right, key exchange MUST + continue using the guessed packet. + + After the KEXINIT packet exchange, the key exchange algorithm is + run. It may involve several packet exchanges, as specified by the + key exchange method. + + 5.2 Output from Key Exchange + + The key exchange produces two values: a shared secret K, and an + exchange hash H. Encryption and authentication keys are derived + from these. The exchange hash H from the first key exchange is + additionally used as the session identifier, which is a unique + identifier for this connection. It is used by authentication + methods as a part of the data that is signed as a proof of + possession of a private key. Once computed, the session + identifier is not changed, even if keys are later re-exchanged. + + + Each key exchange method specifies a hash function that is used in + the key exchange. The same hash algorithm MUST be used in key + derivation. Here, we'll call it HASH. + + + Encryption keys MUST be computed as HASH of a known value and K as + follows: + o Initial IV client to server: HASH(K || H || "A" || session_id) + (Here K is encoded as mpint and "A" as byte and session_id as + raw data."A" means the single character A, ASCII 65). + o Initial IV server to client: HASH(K || H || "B" || session_id) + o Encryption key client to server: HASH(K || H || "C" || + session_id) + + + +Ylonen, et. al. Expires January 12, 2004 [Page 17] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + o Encryption key server to client: HASH(K || H || "D" || + session_id) + o Integrity key client to server: HASH(K || H || "E" || + session_id) + o Integrity key server to client: HASH(K || H || "F" || + session_id) + + Key data MUST be taken from the beginning of the hash output. 128 + bits (16 bytes) SHOULD be used for algorithms with variable-length + keys. For other algorithms, as many bytes as are needed are taken + from the beginning of the hash value. If the key length in longer + than the output of the HASH, the key is extended by computing HASH + of the concatenation of K and H and the entire key so far, and + appending the resulting bytes (as many as HASH generates) to the + key. This process is repeated until enough key material is + available; the key is taken from the beginning of this value. In + other words: + + K1 = HASH(K || H || X || session_id) (X is e.g. "A") + K2 = HASH(K || H || K1) + K3 = HASH(K || H || K1 || K2) + ... + key = K1 || K2 || K3 || ... + + This process will lose entropy if the amount of entropy in K is + larger than the internal state size of HASH. + + 5.3 Taking Keys Into Use + + Key exchange ends by each side sending an SSH_MSG_NEWKEYS message. + This message is sent with the old keys and algorithms. All + messages sent after this message MUST use the new keys and + algorithms. + + + When this message is received, the new keys and algorithms MUST be + taken into use for receiving. + + + This message is the only valid message after key exchange, in + addition to SSH_MSG_DEBUG, SSH_MSG_DISCONNECT and SSH_MSG_IGNORE + messages. The purpose of this message is to ensure that a party + is able to respond with a disconnect message that the other party + can understand if something goes wrong with the key exchange. + Implementations MUST NOT accept any other messages after key + exchange before receiving SSH_MSG_NEWKEYS. + + byte SSH_MSG_NEWKEYS + + + +Ylonen, et. al. Expires January 12, 2004 [Page 18] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + 6. Diffie-Hellman Key Exchange + + The Diffie-Hellman key exchange provides a shared secret that can + not be determined by either party alone. The key exchange is + combined with a signature with the host key to provide host + authentication. + + + In the following description (C is the client, S is the server; p + is a large safe prime, g is a generator for a subgroup of GF(p), + and q is the order of the subgroup; V_S is S's version string; V_C + is C's version string; K_S is S's public host key; I_C is C's + KEXINIT message and I_S S's KEXINIT message which have been + exchanged before this part begins): + + + 1. C generates a random number x (1 < x < q) and computes e = g^x + mod p. C sends "e" to S. + + 2. S generates a random number y (0 < y < q) and computes f = g^y + mod p. S receives "e". It computes K = e^y mod p, H = + hash(V_C || V_S || I_C || I_S || K_S || e || f || K) (these + elements are encoded according to their types; see below), and + signature s on H with its private host key. S sends "K_S || f + || s" to C. The signing operation may involve a second + hashing operation. + + 3. C verifies that K_S really is the host key for S (e.g. using + certificates or a local database). C is also allowed to + accept the key without verification; however, doing so will + render the protocol insecure against active attacks (but may + be desirable for practical reasons in the short term in many + environments). C then computes K = f^x mod p, H = hash(V_C || + V_S || I_C || I_S || K_S || e || f || K), and verifies the + signature s on H. + + Either side MUST NOT send or accept e or f values that are not in + the range [1, p-1]. If this condition is violated, the key + exchange fails. + + + This is implemented with the following messages. The hash + algorithm for computing the exchange hash is defined by the method + name, and is called HASH. The public key algorithm for signing is + negotiated with the KEXINIT messages. + + First, the client sends the following: + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 19] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + byte SSH_MSG_KEXDH_INIT + mpint e + + + The server responds with the following: + + byte SSH_MSG_KEXDH_REPLY + string server public host key and certificates (K_S) + mpint f + string signature of H + + The hash H is computed as the HASH hash of the concatenation of + the following: + + string V_C, the client's version string (CR and NL excluded) + string V_S, the server's version string (CR and NL excluded) + string I_C, the payload of the client's SSH_MSG_KEXINIT + string I_S, the payload of the server's SSH_MSG_KEXINIT + string K_S, the host key + mpint e, exchange value sent by the client + mpint f, exchange value sent by the server + mpint K, the shared secret + + This value is called the exchange hash, and it is used to + authenticate the key exchange. The exchange hash SHOULD be kept + secret. + + + The signature algorithm MUST be applied over H, not the original + data. Most signature algorithms include hashing and additional + padding. For example, "ssh-dss" specifies SHA-1 hashing; in that + case, the data is first hashed with HASH to compute H, and H is + then hashed with SHA-1 as part of the signing operation. + + 6.1 diffie-hellman-group1-sha1 + + The "diffie-hellman-group1-sha1" method specifies Diffie-Hellman + key exchange with SHA-1 as HASH, and the following group: + + The prime p is equal to 2^1024 - 2^960 - 1 + 2^64 * floor( 2^894 + Pi + 129093 ). Its hexadecimal value is: + + 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. + + + +Ylonen, et. al. Expires January 12, 2004 [Page 20] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + In decimal, this value is: + + 179769313486231590770839156793787453197860296048756011706444 + 423684197180216158519368947833795864925541502180565485980503 + 646440548199239100050792877003355816639229553136239076508735 + 759914822574862575007425302077447712589550957937778424442426 + 617334727629299387668709205606050270810842907692932019128194 + 467627007. + + The generator used with this prime is g = 2. The group order q is + (p - 1) / 2. + + This group was taken from the ISAKMP/Oakley specification, and was + originally generated by Richard Schroeppel at the University of + Arizona. Properties of this prime are described in [Orm96]. + + 7. Key Re-Exchange + + Key re-exchange is started by sending an SSH_MSG_KEXINIT packet + when not already doing a key exchange (as described in Section + Section 5.1). When this message is received, a party MUST respond + with its own SSH_MSG_KEXINIT message except when the received + SSH_MSG_KEXINIT already was a reply. Either party MAY initiate + the re-exchange, but roles MUST NOT be changed (i.e., the server + remains the server, and the client remains the client). + + + Key re-exchange is performed using whatever encryption was in + effect when the exchange was started. Encryption, compression, + and MAC methods are not changed before a new SSH_MSG_NEWKEYS is + sent after the key exchange (as in the initial key exchange). Re- + exchange is processed identically to the initial key exchange, + except for the session identifier that will remain unchanged. It + is permissible to change some or all of the algorithms during the + re-exchange. Host keys can also change. All keys and + initialization vectors are recomputed after the exchange. + Compression and encryption contexts are reset. + + + It is recommended that the keys are changed after each gigabyte of + transmitted data or after each hour of connection time, whichever + comes sooner. However, since the re-exchange is a public key + operation, it requires a fair amount of processing power and + should not be performed too often. + + + More application data may be sent after the SSH_MSG_NEWKEYS packet + has been sent; key exchange does not affect the protocols that lie + + + +Ylonen, et. al. Expires January 12, 2004 [Page 21] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + above the SSH transport layer. + + 8. Service Request + + After the key exchange, the client requests a service. The + service is identified by a name. The format of names and + procedures for defining new names are defined in [SSH-ARCH]. + + + Currently, the following names have been reserved: + + ssh-userauth + ssh-connection + + Similar local naming policy is applied to the service names, as is + applied to the algorithm names; a local service should use the + "servicename@domain" syntax. + + byte SSH_MSG_SERVICE_REQUEST + string service name + + If the server rejects the service request, it SHOULD send an + appropriate SSH_MSG_DISCONNECT message and MUST disconnect. + + + When the service starts, it may have access to the session + identifier generated during the key exchange. + + + If the server supports the service (and permits the client to use + it), it MUST respond with the following: + + byte SSH_MSG_SERVICE_ACCEPT + string service name + + Message numbers used by services should be in the area reserved + for them (see Section 6 in [SSH-ARCH]). The transport level will + continue to process its own messages. + + + Note that after a key exchange with implicit server + authentication, the client MUST wait for response to its service + request message before sending any further data. + + 9. Additional Messages + + Either party may send any of the following messages at any time. + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 22] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + 9.1 Disconnection Message + + byte SSH_MSG_DISCONNECT + uint32 reason code + string description [RFC2279] + string language tag [RFC1766] + + This message causes immediate termination of the connection. All + implementations MUST be able to process this message; they SHOULD + be able to send this message. + + The sender MUST NOT send or receive any data after this message, + and the recipient MUST NOT accept any data after receiving this + message. The description field gives a more specific explanation + in a human-readable form. The error code gives the reason in a + more machine-readable format (suitable for localization), and can + have the following values: + + #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 + #define SSH_DISCONNECT_PROTOCOL_ERROR 2 + #define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 + #define SSH_DISCONNECT_RESERVED 4 + #define SSH_DISCONNECT_MAC_ERROR 5 + #define SSH_DISCONNECT_COMPRESSION_ERROR 6 + #define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 + #define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 + #define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 + #define SSH_DISCONNECT_CONNECTION_LOST 10 + #define SSH_DISCONNECT_BY_APPLICATION 11 + #define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 + #define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 + #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 + #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 + + If the description string is displayed, control character + filtering discussed in [SSH-ARCH] should be used to avoid attacks + by sending terminal control characters. + + 9.2 Ignored Data Message + + byte SSH_MSG_IGNORE + string data + + All implementations MUST understand (and ignore) this message at + any time (after receiving the protocol version). No + implementation is required to send them. This message can be used + as an additional protection measure against advanced traffic + analysis techniques. + + + +Ylonen, et. al. Expires January 12, 2004 [Page 23] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + 9.3 Debug Message + + byte SSH_MSG_DEBUG + boolean always_display + string message [RFC2279] + string language tag [RFC1766] + + All implementations MUST understand this message, but they are + allowed to ignore it. This message is used to pass the other side + information that may help debugging. If always_display is TRUE, + the message SHOULD be displayed. Otherwise, it SHOULD NOT be + displayed unless debugging information has been explicitly + requested by the user. + + + The message doesn't need to contain a newline. It is, however, + allowed to consist of multiple lines separated by CRLF (Carriage + Return - Line Feed) pairs. + + + If the message string is displayed, terminal control character + filtering discussed in [SSH-ARCH] should be used to avoid attacks + by sending terminal control characters. + + 9.4 Reserved Messages + + An implementation MUST respond to all unrecognized messages with + an SSH_MSG_UNIMPLEMENTED message in the order in which the + messages were received. Such messages MUST be otherwise ignored. + Later protocol versions may define other meanings for these + message types. + + byte SSH_MSG_UNIMPLEMENTED + uint32 packet sequence number of rejected message + + + 10. Summary of Message Numbers + + The following message numbers have been defined in this protocol: + + #define SSH_MSG_DISCONNECT 1 + #define SSH_MSG_IGNORE 2 + #define SSH_MSG_UNIMPLEMENTED 3 + #define SSH_MSG_DEBUG 4 + #define SSH_MSG_SERVICE_REQUEST 5 + #define SSH_MSG_SERVICE_ACCEPT 6 + + #define SSH_MSG_KEXINIT 20 + + + +Ylonen, et. al. Expires January 12, 2004 [Page 24] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + #define SSH_MSG_NEWKEYS 21 + + /* Numbers 30-49 used for kex packets. + Different kex methods may reuse message numbers in + this range. */ + + #define SSH_MSG_KEXDH_INIT 30 + #define SSH_MSG_KEXDH_REPLY 31 + + + 11. Security Considerations + + This protocol provides a secure encrypted channel over an insecure + network. It performs server host authentication, key exchange, + encryption, and integrity protection. It also derives a unique + session id that may be used by higher-level protocols. + + Full security considerations for this protocol are provided in + Section 8 of [SSH-ARCH] + + 12. Intellectual Property + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described + in this document or the extent to which any license under such + rights might or might not be available; neither does it represent + that it has made any effort to identify any such rights. + Information on the IETF's procedures with respect to rights in + standards-track and standards-related documentation can be found + in BCP-11. Copies of claims of rights made available for + publication and any assurances of licenses to be made available, + or the result of an attempt made to obtain a general license or + permission for the use of such proprietary rights by implementers + or users of this specification can be obtained from the IETF + Secretariat. + + The IETF has been notified of intellectual property rights claimed + in regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + 13. Additional Information + + The current document editor is: Darren.Moffat@Sun.COM. Comments + on this internet draft should be sent to the IETF SECSH working + group, details at: http://ietf.org/html.charters/secsh- + charter.html + + + +Ylonen, et. al. Expires January 12, 2004 [Page 25] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + +References + + [FIPS-186] Federal Information Processing Standards + Publication, ., "FIPS PUB 186, Digital Signature + Standard", May 1994. + + [Orm96] Orman, H., "The Okaley Key Determination Protcol + version1, TR97-92", 1996. + + [RFC2459] Housley, R., Ford, W., Polk, W. and D. Solo, + "Internet X.509 Public Key Infrastructure + Certificate and CRL Profile", RFC 2459, January + 1999. + + [RFC1034] Mockapetris, P., "Domain names - concepts and + facilities", STD 13, RFC 1034, Nov 1987. + + [RFC1766] Alvestrand, H., "Tags for the Identification of + Languages", RFC 1766, March 1995. + + [RFC1950] Deutsch, P. and J-L. Gailly, "ZLIB Compressed Data + Format Specification version 3.3", RFC 1950, May + 1996. + + [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format + Specification version 1.3", RFC 1951, May 1996. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of + ISO 10646", RFC 2279, January 1998. + + [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: + Keyed-Hashing for Message Authentication", RFC + 2104, February 1997. + + [RFC2119] Bradner, S., "Key words for use in RFCs to + Indicate Requirement Levels", BCP 14, RFC 2119, + March 1997. + + [RFC2144] Adams, C., "The CAST-128 Encryption Algorithm", + RFC 2144, May 1997. + + [RFC2440] Callas, J., Donnerhacke, L., Finney, H. and R. + Thayer, "OpenPGP Message Format", RFC 2440, + November 1998. + + [RFC2693] Ellison, C., Frantz, B., Lampson, B., Rivest, R., + Thomas, B. and T. Ylonen, "SPKI Certificate + Theory", RFC 2693, September 1999. + + + +Ylonen, et. al. Expires January 12, 2004 [Page 26] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + [SCHNEIER] Schneier, B., "Applied Cryptography Second + Edition: protocols algorithms and source in code + in C", 1996. + + [TWOFISH] Schneier, B., "The Twofish Encryptions Algorithm: + A 128-Bit Block Cipher, 1st Edition", March 1999. + + [SSH-ARCH] Ylonen, T., "SSH Protocol Architecture", I-D + draft-ietf-architecture-14.txt, July 2003. + + [SSH-TRANS] Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-16.txt, July 2003. + + [SSH-USERAUTH] Ylonen, T., "SSH Authentication Protocol", I-D + draft-ietf-userauth-17.txt, July 2003. + + [SSH-CONNECT] Ylonen, T., "SSH Connection Protocol", I-D draft- + ietf-connect-17.txt, July 2003. + + [SSH-NUMBERS] Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers- + 03.txt, July 2003. + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: ylo@ssh.com + + + Tero Kivinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: kivinen@ssh.com + + + Markku-Juhani O. Saarinen + University of Jyvaskyla + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 27] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + + Timo J. Rinne + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: tri@ssh.com + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 28] + +Internet-Draft SSH Transport Layer Protocol July 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished + to others, and derivative works that comment on or otherwise + explain it or assist in its implementation may be prepared, + copied, published and distributed, in whole or in part, without + restriction of any kind, provided that the above copyright notice + and this paragraph are included on all such copies and derivative + works. However, this document itself may not be modified in any + way, such as by removing the copyright notice or references to the + Internet Society or other Internet organizations, except as needed + for the purpose of developing Internet standards in which case the + procedures for copyrights defined in the Internet Standards + process must be followed, or as required to translate it into + languages other than English. + + The limited permissions granted above are perpetual and will not + be revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on + an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires January 12, 2004 [Page 29] + diff --git a/doc/draft-ietf-secsh-userauth-17.txt b/doc/draft-ietf-secsh-userauth-17.txt new file mode 100644 index 00000000..6624665e --- /dev/null +++ b/doc/draft-ietf-secsh-userauth-17.txt @@ -0,0 +1,840 @@ + + +Network Working Group T. Ylonen +Internet-Draft T. Kivinen +Expires: March 2, 2003 SSH Communications Security Corp + M. Saarinen + University of Jyvaskyla + T. Rinne + S. Lehtinen + SSH Communications Security Corp + September 2002 + + + SSH Authentication Protocol + draft-ietf-secsh-userauth-17.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + 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." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on March 2, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. This document describes the + SSH authentication protocol framework and public key, password, + and host-based client authentication methods. Additional + authentication methods are described in separate documents. The + + + +Ylonen, et. al. Expires March 2, 2003 [Page 1] + +Internet-Draft SSH Authentication Protocol September 2002 + + + SSH authentication protocol runs on top of the SSH transport layer + protocol and provides a single authenticated tunnel for the SSH + connection protocol. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. The Authentication Protocol Framework . . . . . . . . . . . . 3 + 2.1 Authentication Requests . . . . . . . . . . . . . . . . . . . 4 + 2.2 Responses to Authentication Requests . . . . . . . . . . . . . 5 + 2.3 The "none" Authentication Request . . . . . . . . . . . . . . 6 + 2.4 Completion of User Authentication . . . . . . . . . . . . . . 6 + 2.5 Banner Message . . . . . . . . . . . . . . . . . . . . . . . . 6 + 3. Authentication Protocol Message Numbers . . . . . . . . . . . 7 + 4. Public Key Authentication Method: publickey . . . . . . . . . 7 + 5. Password Authentication Method: password . . . . . . . . . . . 9 + 6. Host-Based Authentication: hostbased . . . . . . . . . . . . . 11 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 12 + 8. Intellectual Property . . . . . . . . . . . . . . . . . . . . 12 + 9. Additional Information . . . . . . . . . . . . . . . . . . . . 13 + References . . . . . . . . . . . . . . . . . . . . . . . . . . 13 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 14 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . 15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires March 2, 2003 [Page 2] + +Internet-Draft SSH Authentication Protocol September 2002 + + + 1. Introduction + + The SSH authentication protocol is a general-purpose user + authentication protocol. It is intended to be run over the SSH + transport layer protocol [SSH-TRANS]. This protocol assumes that + the underlying protocols provide integrity and confidentiality + protection. + + This document should be read only after reading the SSH + architecture document [SSH-ARCH]. This document freely uses + terminology and notation from the architecture document without + reference or further explanation. + + The service name for this protocol is "ssh-userauth". + + When this protocol starts, it receives the session identifier from + the lower-level protocol (this is the exchange hash H from the + first key exchange). The session identifier uniquely identifies + this session and is suitable for signing in order to prove + ownership of a private key. This protocol also needs to know + whether the lower-level protocol provides confidentiality + protection. + + 2. The Authentication Protocol Framework + + The server drives the authentication by telling the client which + authentication methods can be used to continue the exchange at any + given time. The client has the freedom to try the methods listed + by the server in any order. This gives the server complete + control over the authentication process if desired, but also gives + enough flexibility for the client to use the methods it supports + or that are most convenient for the user, when multiple methods + are offered by the server. + + Authentication methods are identified by their name, as defined in + [SSH-ARCH]. The "none" method is reserved, and MUST NOT be listed + as supported. However, it MAY be sent by the client. The server + MUST always reject this request, unless the client is to be + allowed in without any authentication, in which case the server + MUST accept this request. The main purpose of sending this + request is to get the list of supported methods from the server. + + The server SHOULD have a timeout for authentication, and + disconnect if the authentication has not been accepted within the + timeout period. The RECOMMENDED timeout period is 10 minutes. + Additionally, the implementation SHOULD limit the number of failed + authentication attempts a client may perform in a single session + (the RECOMMENDED limit is 20 attempts). If the threshold is + + + +Ylonen, et. al. Expires March 2, 2003 [Page 3] + +Internet-Draft SSH Authentication Protocol September 2002 + + + exceeded, the server SHOULD disconnect. + + 2.1 Authentication Requests + + All authentication requests MUST use the following message format. + Only the first few fields are defined; the remaining fields depend + on the authentication method. + + byte SSH_MSG_USERAUTH_REQUEST + string user name (in ISO-10646 UTF-8 encoding [RFC2279]) + string service name (in US-ASCII) + string method name (US-ASCII) + The rest of the packet is method-specific. + + The user name and service are repeated in every new authentication + attempt, and MAY change. The server implementation MUST carefully + check them in every message, and MUST flush any accumulated + authentication states if they change. If it is unable to flush + some authentication state, it MUST disconnect if the user or + service name changes. + + The service name specifies the service to start after + authentication. There may be several different authenticated + services provided. If the requested service is not available, the + server MAY disconnect immediately or at any later time. Sending a + proper disconnect message is RECOMMENDED. In any case, if the + service does not exist, authentication MUST NOT be accepted. + + If the requested user does not exist, the server MAY disconnect, + or MAY send a bogus list of acceptable authentication methods, but + never accept any. This makes it possible for the server to avoid + disclosing information on which accounts exist. In any case, if + the user does not exist, the authentication request MUST NOT be + accepted. + + While there is usually little point for clients to send requests + that the server does not list as acceptable, sending such requests + is not an error, and the server SHOULD simply reject requests that + it does not recognize. + + An authentication request MAY result in a further exchange of + messages. All such messages depend on the authentication method + used, and the client MAY at any time continue with a new + SSH_MSG_USERAUTH_REQUEST message, in which case the server MUST + abandon the previous authentication attempt and continue with the + new one. + + + + + +Ylonen, et. al. Expires March 2, 2003 [Page 4] + +Internet-Draft SSH Authentication Protocol September 2002 + + + 2.2 Responses to Authentication Requests + + If the server rejects the authentication request, it MUST respond + with the following: + + byte SSH_MSG_USERAUTH_FAILURE + string authentications that can continue + boolean partial success + + "Authentications that can continue" is a comma-separated list of + authentication method names that may productively continue the + authentication dialog. + + It is RECOMMENDED that servers only include those methods in the + list that are actually useful. However, it is not illegal to + include methods that cannot be used to authenticate the user. + + Already successfully completed authentications SHOULD NOT be + included in the list, unless they really should be performed again + for some reason. + + "Partial success" MUST be TRUE if the authentication request to + which this is a response was successful. It MUST be FALSE if the + request was not successfully processed. + + When the server accepts authentication, it MUST respond with the + following: + + byte SSH_MSG_USERAUTH_SUCCESS + + Note that this is not sent after each step in a multi-method + authentication sequence, but only when the authentication is + complete. + + The client MAY send several authentication requests without + waiting for responses from previous requests. The server MUST + process each request completely and acknowledge any failed + requests with a SSH_MSG_USERAUTH_FAILURE message before processing + the next request. + + A request that results in further exchange of messages will be + aborted by a second request. It is not possible to send a second + request without waiting for a response from the server, if the + first request will result in further exchange of messages. No + SSH_MSG_USERAUTH_FAILURE message will be sent for the aborted + method. + + SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. When + + + +Ylonen, et. al. Expires March 2, 2003 [Page 5] + +Internet-Draft SSH Authentication Protocol September 2002 + + + SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication + requests received after that SHOULD be silently ignored. + + Any non-authentication messages sent by the client after the + request that resulted in SSH_MSG_USERAUTH_SUCCESS being sent MUST + be passed to the service being run on top of this protocol. Such + messages can be identified by their message numbers (see Section + Message Numbers (Section 3)). + + 2.3 The "none" Authentication Request + + A client may request a list of authentication methods that may + continue by using the "none" authentication method. + + If no authentication at all is needed for the user, the server + MUST return SSH_MSG_USERAUTH_SUCCESS. Otherwise, the server MUST + return SSH_MSG_USERAUTH_FAILURE and MAY return with it a list of + authentication methods that can continue. + + This method MUST NOT be listed as supported by the server. + + 2.4 Completion of User Authentication + + Authentication is complete when the server has responded with + SSH_MSG_USERAUTH_SUCCESS; all authentication related messages + received after sending this message SHOULD be silently ignored. + + After sending SSH_MSG_USERAUTH_SUCCESS, the server starts the + requested service. + + 2.5 Banner Message + + In some jurisdictions, sending a warning message before + authentication may be relevant for getting legal protection. Many + UNIX machines, for example, normally display text from + `/etc/issue', or use "tcp wrappers" or similar software to display + a banner before issuing a login prompt. + + The SSH server may send a SSH_MSG_USERAUTH_BANNER message at any + time before authentication is successful. This message contains + text to be displayed to the client user before authentication is + attempted. The format is as follows: + + byte SSH_MSG_USERAUTH_BANNER + string message (ISO-10646 UTF-8) + string language tag (as defined in [RFC1766]) + + The client SHOULD by default display the message on the screen. + + + +Ylonen, et. al. Expires March 2, 2003 [Page 6] + +Internet-Draft SSH Authentication Protocol September 2002 + + + However, since the message is likely to be sent for every login + attempt, and since some client software will need to open a + separate window for this warning, the client software may allow + the user to explicitly disable the display of banners from the + server. The message may consist of multiple lines. + + If the message string is displayed, control character filtering + discussed in [SSH-ARCH] SHOULD be used to avoid attacks by sending + terminal control characters. + + 3. Authentication Protocol Message Numbers + + All message numbers used by this authentication protocol are in + the range from 50 to 79, which is part of the range reserved for + protocols running on top of the SSH transport layer protocol. + + Message numbers of 80 and higher are reserved for protocols + running after this authentication protocol, so receiving one of + them before authentication is complete is an error, to which the + server MUST respond by disconnecting (preferably with a proper + disconnect message sent first to ease troubleshooting). + + After successful authentication, such messages are passed to the + higher-level service. + + These are the general authentication message codes: + + #define SSH_MSG_USERAUTH_REQUEST 50 + #define SSH_MSG_USERAUTH_FAILURE 51 + #define SSH_MSG_USERAUTH_SUCCESS 52 + #define SSH_MSG_USERAUTH_BANNER 53 + + In addition to the above, there is a range of message numbers + (60..79) reserved for method-specific messages. These messages + are only sent by the server (client sends only + SSH_MSG_USERAUTH_REQUEST messages). Different authentication + methods reuse the same message numbers. + + 4. Public Key Authentication Method: publickey + + The only REQUIRED authentication method is public key + authentication. All implementations MUST support this method; + however, not all users need to have public keys, and most local + policies are not likely to require public key authentication for + all users in the near future. + + With this method, the possession of a private key serves as + authentication. This method works by sending a signature created + + + +Ylonen, et. al. Expires March 2, 2003 [Page 7] + +Internet-Draft SSH Authentication Protocol September 2002 + + + with a private key of the user. The server MUST check that the + key is a valid authenticator for the user, and MUST check that the + signature is valid. If both hold, the authentication request MUST + be accepted; otherwise it MUST be rejected. (Note that the server + MAY require additional authentications after successful + authentication.) + + Private keys are often stored in an encrypted form at the client + host, and the user must supply a passphrase before the signature + can be generated. Even if they are not, the signing operation + involves some expensive computation. To avoid unnecessary + processing and user interaction, the following message is provided + for querying whether authentication using the key would be + acceptable. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "publickey" + boolean FALSE + string public key algorithm name + string public key blob + + Public key algorithms are defined in the transport layer + specification [SSH-TRANS]. The public key blob may contain + certificates. + + Any public key algorithm may be offered for use in authentication. + In particular, the list is not constrained by what was negotiated + during key exchange. If the server does not support some + algorithm, it MUST simply reject the request. + + The server MUST respond to this message with either + SSH_MSG_USERAUTH_FAILURE or with the following: + + byte SSH_MSG_USERAUTH_PK_OK + string public key algorithm name from the request + string public key blob from the request + + To perform actual authentication, the client MAY then send a + signature generated using the private key. The client MAY send + the signature directly without first verifying whether the key is + acceptable. The signature is sent using the following packet: + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "publickey" + + + +Ylonen, et. al. Expires March 2, 2003 [Page 8] + +Internet-Draft SSH Authentication Protocol September 2002 + + + boolean TRUE + string public key algorithm name + string public key to be used for authentication + string signature + + Signature is a signature by the corresponding private key over the + following data, in the following order: + + string session identifier + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "publickey" + boolean TRUE + string public key algorithm name + string public key to be used for authentication + + When the server receives this message, it MUST check whether the + supplied key is acceptable for authentication, and if so, it MUST + check whether the signature is correct. + + If both checks succeed, this method is successful. Note that the + server may require additional authentications. The server MUST + respond with SSH_MSG_USERAUTH_SUCCESS (if no more authentications + are needed), or SSH_MSG_USERAUTH_FAILURE (if the request failed, + or more authentications are needed). + + The following method-specific message numbers are used by the + publickey authentication method. + + /* Key-based */ + #define SSH_MSG_USERAUTH_PK_OK 60 + + + 5. Password Authentication Method: password + + Password authentication uses the following packets. Note that a + server MAY request the user to change the password. All + implementations SHOULD support password authentication. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "password" + boolean FALSE + string plaintext password (ISO-10646 UTF-8) + + Note that the password is encoded in ISO-10646 UTF-8. It is up to + + + +Ylonen, et. al. Expires March 2, 2003 [Page 9] + +Internet-Draft SSH Authentication Protocol September 2002 + + + the server how it interprets the password and validates it against + the password database. However, if the client reads the password + in some other encoding (e.g., ISO 8859-1 (ISO Latin1)), it MUST + convert the password to ISO-10646 UTF-8 before transmitting, and + the server MUST convert the password to the encoding used on that + system for passwords. + + Note that even though the cleartext password is transmitted in the + packet, the entire packet is encrypted by the transport layer. + Both the server and the client should check whether the underlying + transport layer provides confidentiality (i.e., if encryption is + being used). If no confidentiality is provided (none cipher), + password authentication SHOULD be disabled. If there is no + confidentiality or no MAC, password change SHOULD be disabled. + + Normally, the server responds to this message with success or + failure. However, if the password has expired the server SHOULD + indicate this by responding with + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. In anycase the server MUST NOT + allow an expired password to be used for authentication. + + byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ + string prompt (ISO-10646 UTF-8) + string language tag (as defined in [RFC1766]) + + In this case, the client MAY continue with a different + authentication method, or request a new password from the user and + retry password authentication using the following message. The + client MAY also send this message instead of the normal password + authentication request without the server asking for it. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "password" + boolean TRUE + string plaintext old password (ISO-10646 UTF-8) + string plaintext new password (ISO-10646 UTF-8) + + The server must reply to request message with + SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. The meaning of these is as + follows: + + SSH_MSG_USERAUTH_SUCCESS The password has been changed, and + authentication has been successfully completed. + + SSH_MSG_USERAUTH_FAILURE with partial success The password has + + + +Ylonen, et. al. Expires March 2, 2003 [Page 10] + +Internet-Draft SSH Authentication Protocol September 2002 + + + been changed, but more authentications are needed. + + SSH_MSG_USERAUTH_FAILURE without partial success The password + has not been changed. Either password changing was not + supported, or the old password was bad. Note that if the + server has already sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, we + know that it supports changing the password. + + SSH_MSG_USERAUTH_CHANGEREQ The password was not changed because + the new password was not acceptable (e.g. too easy to guess). + + The following method-specific message numbers are used by the + password authentication method. + + #define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 + + + 6. Host-Based Authentication: hostbased + + Some sites wish to allow authentication based on the host where + the user is coming from, and the user name on the remote host. + While this form of authentication is not suitable for high- + security sites, it can be very convenient in many environments. + This form of authentication is OPTIONAL. When used, special care + SHOULD be taken to prevent a regular user from obtaining the + private host key. + + The client requests this form of authentication by sending the + following message. It is similar to the UNIX "rhosts" and + "hosts.equiv" styles of authentication, except that the identity + of the client host is checked more rigorously. + + This method works by having the client send a signature created + with the private key of the client host, which the server checks + with that host's public key. Once the client host's identity is + established, authorization (but no further authentication) is + performed based on the user names on the server and the client, + and the client host name. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "hostbased" + string public key algorithm for host key + string public host key and certificates for client host + string client host name (FQDN; US-ASCII) + string user name on the client host (ISO-10646 UTF-8) + string signature + + + +Ylonen, et. al. Expires March 2, 2003 [Page 11] + +Internet-Draft SSH Authentication Protocol September 2002 + + + Public key algorithm names for use in "public key algorithm for + host key" are defined in the transport layer specification. The + "public host key for client host" may include certificates. + + Signature is a signature with the private host key of the + following data, in this order: + + string session identifier + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "hostbased" + string public key algorithm for host key + string public host key and certificates for client host + string client host name (FQDN; US-ASCII) + string user name on the client host(ISO-10646 UTF-8) + + The server MUST verify that the host key actually belongs to the + client host named in the message, that the given user on that host + is allowed to log in, and that the signature is a valid signature + on the appropriate value by the given host key. The server MAY + ignore the client user name, if it wants to authenticate only the + client host. + + It is RECOMMENDED that whenever possible, the server perform + additional checks to verify that the network address obtained from + the (untrusted) network matches the given client host name. This + makes exploiting compromised host keys more difficult. Note that + this may require special handling for connections coming through a + firewall. + + 7. Security Considerations + + The purpose of this protocol is to perform client user + authentication. It assumed that this runs over a secure transport + layer protocol, which has already authenticated the server + machine, established an encrypted communications channel, and + computed a unique session identifier for this session. The + transport layer provides forward secrecy for password + authentication and other methods that rely on secret data. + + Full security considerations for this protocol are provided in + Section 8 of [SSH-ARCH] + + 8. Intellectual Property + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + + + +Ylonen, et. al. Expires March 2, 2003 [Page 12] + +Internet-Draft SSH Authentication Protocol September 2002 + + + pertain to the implementation or use of the technology described + in this document or the extent to which any license under such + rights might or might not be available; neither does it represent + that it has made any effort to identify any such rights. + Information on the IETF's procedures with respect to rights in + standards-track and standards-related documentation can be found + in BCP-11. Copies of claims of rights made available for + publication and any assurances of licenses to be made available, + or the result of an attempt made to obtain a general license or + permission for the use of such proprietary rights by implementers + or users of this specification can be obtained from the IETF + Secretariat. + + The IETF has been notified of intellectual property rights claimed + in regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + 9. Additional Information + + The current document editor is: Darren.Moffat@Sun.COM. Comments + on this internet draft should be sent to the IETF SECSH working + group, details at: http://ietf.org/html.charters/secsh- + charter.html + +References + + [RFC1766] Alvestrand, H., "Tags for the Identification of + Languages", RFC 1766, March 1995. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of + ISO 10646", RFC 2279, January 1998. + + [SSH-ARCH] Ylonen, T., "SSH Protocol Architecture", I-D + draft-ietf-architecture-14.txt, July 2003. + + [SSH-TRANS] Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-16.txt, July 2003. + + [SSH-USERAUTH] Ylonen, T., "SSH Authentication Protocol", I-D + draft-ietf-userauth-17.txt, July 2003. + + [SSH-CONNECT] Ylonen, T., "SSH Connection Protocol", I-D draft- + ietf-connect-17.txt, July 2003. + + [SSH-NUMBERS] Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers- + 03.txt, July 2003. + + + +Ylonen, et. al. Expires March 2, 2003 [Page 13] + +Internet-Draft SSH Authentication Protocol September 2002 + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: ylo@ssh.com + + + Tero Kivinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: kivinen@ssh.com + + + Markku-Juhani O. Saarinen + University of Jyvaskyla + + + Timo J. Rinne + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: tri@ssh.com + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: sjl@ssh.com + + + + + + + + + + + +Ylonen, et. al. Expires March 2, 2003 [Page 14] + +Internet-Draft SSH Authentication Protocol September 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished + to others, and derivative works that comment on or otherwise + explain it or assist in its implementation may be prepared, + copied, published and distributed, in whole or in part, without + restriction of any kind, provided that the above copyright notice + and this paragraph are included on all such copies and derivative + works. However, this document itself may not be modified in any + way, such as by removing the copyright notice or references to the + Internet Society or other Internet organizations, except as needed + for the purpose of developing Internet standards in which case the + procedures for copyrights defined in the Internet Standards + process must be followed, or as required to translate it into + languages other than English. + + The limited permissions granted above are perpetual and will not + be revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on + an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Ylonen, et. al. Expires March 2, 2003 [Page 15] + diff --git a/doc/libssh-0.2-api-1.txt b/doc/libssh-0.2-api-1.txt new file mode 100644 index 00000000..ff35b392 --- /dev/null +++ b/doc/libssh-0.2-api-1.txt @@ -0,0 +1,370 @@ + The new libssh 0.2 API + ---------------------- + +Version 1 + +A. Introduction +--------------- + +With the time from the first release of libssh, I have received lots of +comments about the current API. Myself, I found it quite limiting when doing +my first libssh-server drafts. Thus, I am moving to a stronger API. +This API must still be simple. I am not introducing complex changes. An API +well designed must hide the implementation details. Implementation can change +easily within bugfixes - but API cannot change each release. + +To the people already using libssh 0.11 : sorry. Once I have the complete API +redesigned, I will write a migration paper. It won't be too hard normally. + +Here are the things that were lacking in the previous API and *must* change: + +* A non-blocking mode connection type +* Functions to relegate File descriptor listening to Calling functions and to + the programmer. (I'll explain later). +* Along with that, good buffering system (well, it's not an API but). +* Leave the "functions returns a pointer when it works and NULL when it does + not work". It gives serious problems to implement bindings (A C++ + constructor should not fail and should not depend on a network thing +* Make the Session structure an abstract structure that can work with both + client and *servers*. That mean we should have a Server object which listen + to clients on a bound port, does the different handshakes and return a + session. + Since C is not per se an Object language, I won't use inheritance between + objects. +* This same server thing must provide the reverse capabilities than the + client. That is, accept the handshake, in a nonblocking way. Accept channel + requests, or send them to the controller program. +* Support for program forking : Imagine you have a Ssh server object. You + accept a connection and receive a session, then you receive a channel. You + may want to keep the good old days fork() tricks. Libssh will give a way to + destroy handlers from sessions which belong to an other process without + disturbing the session. +* So often I received the comment back saying that it was not clear why a + session or a channel was terminated. This is over. +* And of course I received lot of mails about the fact I'm doing namespace + polution. this will be resolved this time. +So, please read this draft not as a formal documentation but like a roadmap of +things that each kind of object must do. + +B. Description of objects and functions + +Options structure +~~~~~~~~~~~~~~~~~ + +struct ssh_options *ssh_options_new() + +ssh_options_getopt(options, *argc, argv) + +ssh_options_copy(options) + +char ** ssh_options_get_supported_algos(options,type) + returns a list of the algos supported by libssh, type being one of + SSH_HOSTKEYS, SSH_KEX, SSH_CRYPT, SSH_MAC, SSH_COMP, SSH_LANG + +ssh_options_set_wanted_algos(options,type, char *list) +list being comma-separated list of algos, and type being the upper constants +but with _C_S or _S_V added to them. + +ssh_options_set_port(options, port) + +ssh_options_set_host(options, host) + +ssh_options_set_fd(options, fd) + +ssh_options_set_bind(options, bindaddr, port) +this options sets the address to bind for a client *or* a server. a port of +zero means whatever port is free (what most clients want). + +ssh_options_set_username(options, username) + +ssh_options_set_connect_timeout(options, seconds, usec) + +ssh_options_set_ssh_dir(options, dir) +ssh_options_set_known_hosts_file(options, file) +ssh_options_set_identity(options, file) + +ssh_options_set_banner(options, banner) +ssh_options_allow_ssh1(options, bool allow) +ssh_options_allow_ssh2(options, bool allow) + +options_set_status_callback has moved into ssh_* functions. + +ssh_session Structure +~~~~~~~~~~~~~~~~~~~~~ + +This session structure represents a ssh socket to a server *or* a client. + +ssh_session *ssh_new() + +ssh_set_options(ssh_session,ssh_options) + +ssh_connect(session); + it will return some status describing at which point of the connection it is, + or an error code. If the connection method is non-blocking, the function + will be called more than once, though the return value SSH_AGAIN. + +ssh_set_blocking(session, bool blocking) + set blocking mode or non blocking mode. + +ssh_get_fd(session) + get the currently used connection file descriptor or equivalent (windows) + +ssh_set_fd_toread(session) +ssh_set_fd_towrite(session) +ssh_set_fd_except(session) + Serve to notify the library that data is actualy available to be read on the + file descriptor socket. why ? because on most platforms select can't be done + twice on the same socket when the first reported data to read or to write + +ssh_get_status(session) + Returns the current status bitmask : connection Open or closed, data + pending to read or not (even if connection closed), connection closed on + error or on an exit message + +ssh_get_disconnect_message(session) + Returns the connection disconnect error/exit message + +ssh_get_pubkey_hash(session, hash) + get the public key hash from the server. + +ssh_is_server_known(session) +ssh_write_knownhost(session) + these 2 functions will be kept + +ssh_disconnect(session) + standard disconnect + +ssh_disconnect_error(session,error code, message) + disconnect with a message + +ssh_set_username(session) + set the user name to log in + +ssh_userauth_* functions will be kept as they are now, excepted the fact that +the username field will disapear. +the public key mechanism may get some more functions, like retrieving a public +key from a private key and authenticating without a public key. + +ssh_get_issue_banner(session) + get the issue banner from the server, that is the welcome message. + +ssh_silent_free(session) + This function silently free all data structures used by the session and + closes the socket. It may be used for instance when the process forked and + doesn't want to keep track of this session. This is obviously not possible to + do with separate channels. + +The channel_struct structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The channels will change a bit. the constructor thing will change, and the way +to multiplex different connections will change too. channel functions will be +prefixed with "ssh_" + +struct channel_struct *ssh_channel_new() + +ssh_channel_open_session(channel) + will return if the channel allocation failed or not. + +ssh_channel_open_forward(channel, ...) won't change. it will report an error if +the channel allocation failed. + +ssh_channel_send_eof(channel) + send EOF +ssh_channel_close(channel) + closes a channel but doesn't destroy it. you may read unread data still in + the buffer. Once you closed the buffer, the other party can't send you data, + while it could still do it if you only sent an EOF. +ssh_channel_is_closed(channel) + returns true if the channel was closed at one of both sides. a closed chan + may still have data to read, if you closed yourself the connection. otherwise + (you didn't close it) the closed notification only comes when you read the + last buffer byte, or when trying to write into the channel (the SIGPIPE-like + behaviour). + +ssh_channel_is_eof(channel) + reports if the other side has sent an EOF. This functions returns FALSE if + there is still data to read. A closed channel is always EOF. +ssh_channel_free(channel) + completely free the channel. closes it before if it was not done. + +ssh_channel_request_env(channel, name, value) + set an environment variable. + +ssh_channel_request_pty(channel) +ssh_channel_request_pty_size() +ssh_channel_change_pty_size() +ssh_channel_request_shell() +ssh_channel_request_exec() +ssh_channel_request_subsystem() +These functions won't change. + +int ssh_channel_write(channel,data, len,stderr) + Depending on the blocking/non blocking mode of the channel, the behaviour may + change. + stderr is the extended buffer. It's generaly only a server->client stream. + +ssh_channel_set_blocking(bool blocking) + +int ssh_channel_read(channel, buffer, maxlen, is_stderr) + the behaviour will be this one: + -if the chan is in non blocking mode, it will poll what's available to read + and return this. otherwise (nothing to read) it will return 0. + -if the chan is blocking, it will block until at least one byte is + available. +ssh_channel_nonblocking disapears for the later reason. + +int channel_poll(channel, is_stderr) + polls the network and reports the number of bytes ready to be read in the + chan. + +ssh_session ssh_channel_get_session(channel) + returns the session pointer associated to the channel, for simplicity + reasons. + +int ssh_channel_select(CHANNELS *readchans, CHANNELS *writechans, CHANNELS + *exceptchans, struct timeval *timeout) + This function won't work the same way ssh_select did. + I removed the custom file descriptor thing for 2 reasons: + 1- it's not windows compliant. D'ouh ! + 2- most programmers won't want to depend on libssh for socket multiplexing. + that's why i let the programmer poll the fds himself and then use + ssh_set_fd_toread, towrite or except. Then, he may use ssh_channel_select + with a NULL timeout to poll which channels have something to read, write or + error report. + Here is how it's going to work. The coder sets 3 different arrays with the + channels he wants to select(), the last entry being a NULL pointer. The + function will first poll them and return the chans that must be + read/write/excepted. If nothing has this state, the function will select() + using the timeout. + The function will return 0 if everything is ok, SSH_TIMEOUT or SSH_EINTR if + the select was interrupted by a signal. It is dangerous to execute any + channel-related functions into signal handlers. they should set a flag that + you read into your loop. this "trap" (SSH_EINTR) will permit you to catch + them faster and make your program responsive and look fast. + the function will return -1 if a serious problem happens. + + +Error handling +~~~~~~~~~~~~~~ + +when an error happens, the programmer can get the error code and description +with ssh_get_error(session). the creation of a failess constructor for +ssh_session was needed for this reason. + +ssh_get_error_code(session) will return an error code into this subset: + SSH_NO_ERROR : no error :) + SSH_REQUEST_DENIED : you request for a functionality or a service that is not + allowed. The session can continue. + SSH_FATAL : Unrecoverable error. The session can't continue and you should + disconnect the session. It includes the connection being cut without a + disconnect() message. + If a disconnect() message or the channel was closed, a read on such a channel + won't produce an error. otherwise it will return -1 with a SSH_FATAL error + code. + +Server socket binding +~~~~~~~~~~~~~~~~~~~~~ + +It is not possible to bind a socket for ssh with a SSH_SESSION type, because a +single bound port may lead to multiple ssh connections. That's why the +SSH_BIND structure must be created. It uses options from the SSH_OPTIONS +structure. + +SSH_BIND *ssh_bind_new() +creates a structure +ssh_bind_set_options(bind, options) +set the option structure +int ssh_bind_listen(bind) + bind and listen to the port. This call is not blocking. if some error + happens, it returns -1 and the error code can be found with perror(). + +ssh_bind_set_blocking(bind, bool blocking) + should ssh_bind_accept() block or not. + +int ssh_bind_get_fd(bind) + return the bound file descriptor, that is the listener socket. you may put it + into a select() in your code to detect a connection attempt. + +ssh_bind_set_fd_toaccept(bind) + say that the listener socket has a connection to accept (to avoid + ssh_bind_accept() to do a select on it). + +SSH_SESSION *ssh_bind_accept(bind) + return a server handle to a ssh session. if the mode is blocking, the + function will always return a pointer to a session. if the mode is not + blocking, the function can return NULL if there is no connection to accept. + +This SSH_SESSION handle must then pass through the functions explained above. + + +*server functions * + +int ssh_accept(session) + when a new connection is accepted, the handshake must be done. this function + will do the banner handshake and the key exchange. + it will return SSH_AGAIN if the session mode is non blocking, and the + function must be called again until an error occurs or the kex is done. + +Here, I had a few choises about *how* to implement the message parsing as a +server. There are multiple ways to do it, one being callbacks and one being +"Message" reading, parsing and then choice going to the user to use it and +answer. I've choosen the latter because i believe it's the stronger method. +A ssh server can receive 30 different kind of messages having to be dealt by +the high level routines, like channel request_shell or authentication. Having +a callback for all of them would produce a huge kludge of callbacks, with +no relations on when there were called etc. +A message based parsing allows the user to filtrate the messages he's +interested into and to use a default answer for the others. Then, the callback +thing is still possible to handle through a simple message code/callback +function array. + +I did not define yet what it would look like, but i'm sure there will be a +SSH_MESSAGE (they won't have a 1/1 correspondance with ssh packets) which will +be read through +SSH_MESSAGE *ssh_server_read_message(session). +with all of the non-blocking stuff in head like returning NULL if the message +is not full. +Then, the message can be parsed, ie +int ssh_message_get_code(message) +which will return SSH_MESSAGE_AUTH +then +int ssh_message_get_subcode(message) +which then will returh SSH_MESSAGE_AUTH_PASSWORD or _NONE or _PUBKEY etc. + +Then, once the message was parsed, the message will have to be answered, ie +with the generic functions like +ssh_message_accept(message) which says 'Ok your request is accepted' or +ssh_message_deny(message) which says 'Your request is refused'. + +There would be specific message answer functions for some kind of messages +like the authentication one. you may want to reply that the authentication is +Partial rather than denied, and that you still accept some kind of auths, like +ssh_message_auth_reply(message,SSH_AUTH_PARTIAL,SSH_AUTH_PASSWORD | +SSH_AUTH_PUBKEY | SSH_AUTH_KEYBINT); + +I won't let the user have to deal with the channels himself. When a channel is +going to be created by the remote size, a message will come asking to open a +channel. the programmer can either deny or accept, in which case a CHANNEL +object will be created and returned to the programmer. then, all standard +channel functions will run. + +C. Change log of this document + +2. ssh_options_set_username finaly is kept into the options, because it can be +set by ssh_options_getopt() + +1. first release + +D. End notes + +I think libssh must have a very simple to use, powerful and exhaustive API. It +must have no design flaw either. +While I got some good experience at the SSH protocol, I've never writen +more-than-100 lines programs than use libssh and I don't really know the +problems of the library. I'd like people who don't understand some detail into +the API I describe here, who have comments or opinions about it to write me +the soonest possible to limit the damages if I made something the completely +wrong way. +Thanks for your patience. + diff --git a/doc/protocol-1.5.txt b/doc/protocol-1.5.txt new file mode 100644 index 00000000..9d49f6a9 --- /dev/null +++ b/doc/protocol-1.5.txt @@ -0,0 +1,1501 @@ +Network Working Group T. Ylonen +Internet-Draft Helsinki University of Technology +draft-ylonen-ssh-protocol-00.txt 15 November 1995 +Expires: 15 May 1996 + + + The SSH (Secure Shell) Remote Login Protocol + +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. + +Introduction + + SSH (Secure Shell) is a program to log into another computer over a network, to execute commands in a remote machine, and to move files from one machine to another. It provides strong authentication and secure communications over insecure networks. Its features include + the following: + + o Closes several security holes (e.g., IP, routing, and DNS spoofing). New authentication methods: .rhosts together with RSA [RSA] based host authentication, and pure RSA authentication. + + o All communications are automatically and transparently encrypted. Encryption is also used to protect integrity. + + o X11 connection forwarding provides secure X11 sessions. + + o Arbitrary TCP/IP ports can be redirected over the encrypted channel in both directions. + + o Client RSA-authenticates the server machine in the beginning of every connection to prevent trojan horses (by routing or DNS spoofing) and man-in-the-middle attacks, and the server RSA-authenticates the client machine before accepting .rhosts or /etc/hosts.equiv authentication (to prevent DNS, routing, or IP spoofing). + + o An authentication agent, running in the user's local workstation or laptop, can be used to hold the user's RSA authentication keys. + + The goal has been to make the software as easy to use as possible for ordinary users. The protocol has been designed to be as secure as possible while making it possible to create implementations that are easy to use and install. The sample implementation has a number of convenient features that are not described in this document as they are not relevant for the protocol. + + +Overview of the Protocol + + The software consists of a server program running on a server machine, and a client program running on a client machine (plus a few auxiliary programs). The machines are connected by an insecure IP [RFC0791] network (that can be monitored, tampered with, and spoofed by hostile parties). + + A connection is always initiated by the client side. The server listens on a specific port waiting for connections. Many clients may connect to the same server machine. + + The client and the server are connected via a TCP/IP [RFC0793] socket that is used for bidirectional communication. Other types of transport can be used but are currently not defined. + + When the client connects the server, the server accepts the connection and responds by sending back its version identification string. + The client parses the server's identification, and sends its own identification. The purpose of the identification strings is to validate that the connection was to the correct port, declare the protocol version number used, and to declare the software version used on each side (for debugging purposes). The identification strings are human-readable. If either side fails to understand or support the other side's version, it closes the connection. + + After the protocol identification phase, both sides switch to a packet based binary protocol. The server starts by sending its host key (every host has an RSA key used to authenticate the host), server key (an RSA key regenerated every hour), and other information to the client. The client then generates a 256 bit session key, encrypts it using both RSA keys (see below for details), and sends the encrypted session key and selected cipher type to the server. Both sides then turn on encryption using the selected algorithm and key. The server sends an encrypted confirmation message to the client. + + The client then authenticates itself using any of a number of authentication methods. The currently supported authentication methods are .rhosts or /etc/hosts.equiv authentication (disabled by default), the same with RSA-based host authentication, RSA authentication, and password authentication. + + After successful authentication, the client makes a number of requests to prepare for the session. Typical requests include allocating a pseudo tty, starting X11 [X11] or TCP/IP port forwarding, + starting authentication agent forwarding, and executing the shell or a command. + + When a shell or command is executed, the connection enters interactive session mode. In this mode, data is passed in both directions, new forwarded connections may be opened, etc. The interactive session normally terminates when the server sends the exit status of the program to the client. + + + The protocol makes several reservations for future extensibility. First of all, the initial protocol identification messages include the protocol version number. Second, the first packet by both sides includes a protocol flags field, which can be used to agree on extensions in a compatible manner. Third, the authentication and session preparation phases work so that the client sends requests to the server, and the server responds with success or failure. If the client sends a request that the server does not support, the server simply returns failure for it. This permits compatible addition of new authentication methods and preparation operations. The interactive session phase, on the other hand, works asynchronously and does not permit the use of any extensions (because there is no easy and reliable way to signal rejection to the other side and problems would be hard to debug). Any compatible extensions to this phase must be agreed upon during any of the earlier phases. + +The Binary Packet Protocol + + After the protocol identification strings, both sides only send specially formatted packets. The packet layout is as follows: + + o Packet length: 32 bit unsigned integer, coded as four 8-bit bytes, msb first. Gives the length of the packet, not including the length field and padding. The maximum length of a packet (not including the length field and padding) is 262144 bytes. + + o Padding: 1-8 bytes of random data (or zeroes if not encrypting). The amount of padding is (8 - (length % 8)) bytes (where % stands for the modulo operator). The rationale for always having some random padding at the beginning of each packet is to make known plaintext attacks more difficult. + + o Packet type: 8-bit unsigned byte. The value 255 is reserved for future extension. + + o Data: binary data bytes, depending on the packet type. The number of data bytes is the "length" field minus 5. + + o Check bytes: 32-bit crc, four 8-bit bytes, msb first. The crc is the Cyclic Redundancy Check, with the polynomial 0xedb88320, of the Padding, Packet type, and Data fields. The crc is computed before any encryption. + + The packet, except for the length field, may be encrypted using any of a number of algorithms. The length of the encrypted part (Padding + Type + Data + Check) is always a multiple of 8 bytes. Typically the cipher is used in a chained mode, with all packets chained together as if it was a single data stream (the length field is never included in the encryption process). Details of encryption are described below. + + When the session starts, encryption is turned off. Encryption is enabled after the client has sent the session key. The encryption algorithm to use is selected by the client. + + +Packet Compression + + If compression is supported (it is an optional feature, see SSH_CMSG_REQUEST_COMPRESSION below), the packet type and data fields of the packet are compressed using the gzip deflate algorithm [GZIP]. + If compression is in effect, the packet length field indicates the length of the compressed data, plus 4 for the crc. The amount of padding is computed from the compressed data, so that the amount of data to be encrypted becomes a multiple of 8 bytes. + + When compressing, the packets (type + data portions) in each direction are compressed as if they formed a continuous data stream, with only the current compression block flushed between packets. This corresponds to the GNU ZLIB library Z_PARTIAL_FLUSH option. The compression dictionary is not flushed between packets. The two directions are compressed independently of each other. + + +Packet Encryption + + The protocol supports several encryption methods. During session initialization, the server sends a bitmask of all encryption methods that it supports, and the client selects one of these methods. The client also generates a 256-bit random session key (32 8-bit bytes) and sends it to the server. + + The encryption methods supported by the current implementation, and their codes are: + + SSH_CIPHER_NONE 0 No encryption + SSH_CIPHER_IDEA 1 IDEA in CFB mode + SSH_CIPHER_DES 2 DES in CBC mode + SSH_CIPHER_3DES 3 Triple-DES in CBC mode + SSH_CIPHER_RC4 5 RC4 + + All implementations are required to support SSH_CIPHER_3DES. Supporting SSH_CIPHER_IDEA, SSH_CIPHER_RC4, and SSH_CIPHER_NONE is recommended. Other ciphers may be added at a later time; support for them is optional. + + For encryption, the encrypted portion of the packet is considered a linear byte stream. The length of the stream is always a multiple of 8. The encrypted portions of consecutive packets (in the same direction) are encrypted as if they were a continuous buffer (that is, any initialization vectors are passed from the previous packet to the next packet). Data in each direction is encrypted independently. + + SSH_CIPHER_DES + The key is taken from the first 8 bytes of the session key. The least significant bit of each byte is ignored. This results in 56 bits of key data. DES [DES] is used in CBC mode. The iv (initialization vector) is initialized to all zeroes. + + SSH_CIPHER_3DES + The variant of triple-DES used here works as follows: there are three independent DES-CBC ciphers, with independent initialization vectors. The data (the whole encrypted data stream) is first encrypted with the first cipher, then decrypted with the second cipher, and finally encrypted with the third cipher. All these operations are performed in CBC mode. + + The key for the first cipher is taken from the first 8 bytes of the session key; the key for the next cipher from the next 8 bytes, and the key for the third cipher from the following 8 bytes. All three initialization vectors are initialized to zero. + + (Note: the variant of 3DES used here differs from some other descriptions.) + + SSH_CIPHER_IDEA + The key is taken from the first 16 bytes of the session key. IDEA [IDEA] is used in CFB mode. The initialization vector is initialized to all zeroes. + + SSH_CIPHER_RC4 + The first 16 bytes of the session key are used as the key for the server to client direction. The remaining 16 bytes are used as the key for the client to server direction. This gives independent 128-bit keys for each direction. + + This algorithm is the alleged RC4 cipher posted to the Usenet in 1995. It is widely believed to be equivalent with the original RSADSI RC4 cipher. This is a very fast algorithm. + + +Data Type Encodings + + The Data field of each packet contains data encoded as described in this section. There may be several data items; each item is coded as described here, and their representations are concatenated together (without any alignment or padding). + + Each data type is stored as follows: + + 8-bit byte + The byte is stored directly as a single byte. + + 32-bit unsigned integer + Stored in 4 bytes, msb first. + + Arbitrary length binary string + First 4 bytes are the length of the string, msb first (not including the length itself). The following "length" bytes are the string value. There are no terminating null characters. + + Multiple-precision integer + First 2 bytes are the number of bits in the integer, msb first (for example, the value 0x00012345 would have 17 bits). The value zero has zero bits. It is permissible that the number of bits be larger than the real number of bits. + + The number of bits is followed by (bits + 7) / 8 bytes of binary data, msb first, giving the value of the integer. + + +TCP/IP Port Number and Other Options + + The server listens for connections on TCP/IP port 22. + + The client may connect the server from any port. However, if the client wishes to use any form of .rhosts or /etc/hosts.equiv authentication, it must connect from a privileged port (less than 1024). + + For the IP Type of Service field [RFC0791], it is recommended that interactive sessions (those having a user terminal or forwarding X11 connections) use the IPTOS_LOWDELAY, and non-interactive connections use IPTOS_THROUGHPUT. + + It is recommended that keepalives are used, because otherwise programs on the server may never notice if the other end of the connection is rebooted. + + +Protocol Version Identification + + After the socket is opened, the server sends an identification string, which is of the form "SSH-.-\n", where and are integers and specify the protocol version number (not software distribution version). is server side software version string (max 40 characters); it is not interpreted by the remote side but may be useful for debugging. + + The client parses the server's string, and sends a corresponding string with its own information in response. If the server has lower version number, and the client contains special code to emulate it, + the client responds with the lower number; otherwise it responds with its own number. The server then compares the version number the client sent with its own, and determines whether they can work together. The server either disconnects, or sends the first packet using the binary packet protocol and both sides start working according to the lower of the protocol versions. + + By convention, changes which keep the protocol compatible with previous versions keep the same major protocol version; changes that are not compatible increment the major version (which will hopefully never happen). The version described in this document is 1.5. + +Key Exchange and Server Host Authentication + + The first message sent by the server using the packet protocol is SSH_SMSG_PUBLIC_KEY. It declares the server's host key, server public key, supported ciphers, supported authentication methods, and flags for protocol extensions. It also contains a 64-bit random number (cookie) that must be returned in the client's reply (to make IP spoofing more difficult). No encryption is used for this message. + + Both sides compute a session id as follows. The modulus of the host key is interpreted as a byte string (without explicit length field, with minimum length able to hold the whole value), most significant byte first. This string is concatenated with the server key interpreted the same way. Additionally, the cookie is concatenated with this. Both sides compute MD5 of the resulting string. The resulting 16 bytes (128 bits) are stored by both parties and are called the session id. + + In other words, session_id = MD5(hostkey->n || servkey->n || cookie) + + The client responds with a SSH_CMSG_SESSION_KEY message, which contains the selected cipher type, a copy of the 64-bit cookie sent by the server, client's protocol flags, and a session key encrypted with both the server's host key and server key. No encryption is used for this message. +The session key is 32 8-bit bytes (a total of 256 random bits generated by the client). The client first xors the 16 bytes of the session id with the first 16 bytes of the session key. The resulting string is then encrypted using the smaller key (one with smaller modulus), and the result is then encrypted using the other key. The number of bits in the public modulus of the two keys must differ by at least 128 bits. + + At each encryption step, a multiple-precision integer is constructed from the data to be encrypted as follows (the integer is here interpreted as a sequence of bytes, msb first; the number of bytes is the number of bytes needed to represent the modulus). + + The most significant byte (which is only partial as the value must be less than the public modulus, which is never a power of two) is zero. + + The next byte contains the value 2 (which stands for public-key encrypted data in the PKCS standard [PKCS#1]). Then, there are nonzero random bytes to fill any unused space, a zero byte, and the data to be encrypted in the least significant bytes, the last byte of the data in the least significant byte. + + This algorithm is used twice. First, it is used to encrypt the 32 random bytes generated by the client to be used as the session key (xored by the session id). This value is converted to an integer as described above, and encrypted with RSA using the key with the smaller modulus. The resulting integer is converted to a byte stream, msb first. This byte stream is padded and encrypted identically using the key with the larger modulus. + + After the client has sent the session key, it starts to use the selected algorithm and key for decrypting any received packets, and for encrypting any sent packets. Separate ciphers are used for different directions (that is, both directions have separate initialization vectors or other state for the ciphers). + + When the server has received the session key message, and has turned on encryption, it sends a SSH_SMSG_SUCCESS message to the client. + The recommended size of the host key is 1024 bits, and 768 bits for the server key. The minimum size is 512 bits for the smaller key. + +Declaring the User Name + + The client then sends a SSH_CMSG_USER message to the server. This message specifies the user name to log in as. + + The server validates that such a user exists, checks whether authentication is needed, and responds with either SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE. SSH_SMSG_SUCCESS indicates that no authentication is needed for this user (no password), and authentication phase has now been completed. SSH_SMSG_FAILURE indicates that authentication is needed (or the user does not exist). + + If the user does not exist, it is recommended that this returns failure, but the server keeps reading messages from the client, and responds to any messages (except SSH_MSG_DISCONNECT, SSH_MSG_IGNORE, and SSH_MSG_DEBUG) with SSH_SMSG_FAILURE. This way the client cannot be certain whether the user exists. + + +Authentication Phase + + Provided the server didn't immediately accept the login, an authentication exchange begins. The client sends messages to the server requesting different types of authentication in arbitrary order as many times as desired (however, the server may close the connection after a timeout). The server always responds with SSH_SMSG_SUCCESS if it has accepted the authentication, and with SSH_SMSG_FAILURE if it has denied authentication with the requested method or it does not recognize the message. Some authentication methods cause an exchange of further messages before the final result is sent. The authentication phase ends when the server responds with success. + + The recommended value for the authentication timeout (timeout before disconnecting if no successful authentication has been made) is 5 minutes. + + The following authentication methods are currently supported: + + SSH_AUTH_RHOSTS 1 .rhosts or /etc/hosts.equiv + SSH_AUTH_RSA 2 pure RSA authentication + SSH_AUTH_PASSWORD 3 password authentication + SSH_AUTH_RHOSTS_RSA 4 .rhosts with RSA host authentication + + + SSH_AUTH_RHOSTS + + This is the authentication method used by rlogin and rsh [RFC1282]. + + The client sends SSH_CMSG_AUTH_RHOSTS with the client-side user name as an argument. + + The server checks whether to permit authentication. On UNIX systems, this is usually done by checking /etc/hosts.equiv, and .rhosts in the user's home directory. The connection must come from a privileged port. + + It is recommended that the server checks that there are no IP options (such as source routing) specified for the socket before accepting this type of authentication. The client host name should be reverse-mapped and then forward mapped to ensure that it has the proper IP-address. + + This authentication method trusts the remote host (root on the remote host can pretend to be any other user on that host), the name services, and partially the network: anyone who can see packets coming out from the server machine can do IP-spoofing and pretend to be any machine; however, the protocol prevents blind IP-spoofing (which used to be possible with rlogin). + + Many sites probably want to disable this authentication method because of the fundamental insecurity of conventional .rhosts or /etc/hosts.equiv authentication when faced with spoofing. It is recommended that this method not be supported by the server by default. + + SSH_AUTH_RHOSTS_RSA + + In addition to conventional .rhosts and hosts.equiv authentication, this method additionally requires that the client host be authenticated using RSA. + + The client sends SSH_CMSG_AUTH_RHOSTS_RSA specifying the client-side user name, and the public host key of the client host. + + The server first checks if normal .rhosts or /etc/hosts.equiv authentication would be accepted, and if not, responds with SSH_SMSG_FAILURE. Otherwise, it checks whether it knows the host key for the client machine (using the same name for the host that was used for checking the .rhosts and /etc/hosts.equiv files). If it does not know the RSA key for the client, access is denied and SSH_SMSG_FAILURE is sent. + + If the server knows the host key of the client machine, it verifies that the given host key matches that known for the client. + If not, access is denied and SSH_SMSG_FAILURE is sent. + + The server then sends a SSH_SMSG_AUTH_RSA_CHALLENGE message containing an encrypted challenge for the client. The challenge is 32 8-bit random bytes (256 bits). When encrypted, the highest (partial) byte is left as zero, the next byte contains the value 2, the following are non-zero random bytes, followed by a zero byte, and the challenge put in the remaining bytes. This is then encrypted using RSA with the client host's public key. + (The padding and encryption algorithm is the same as that used for the session key.) + + The client decrypts the challenge using its private host key, concatenates this with the session id, and computes an MD5 checksum of the resulting 48 bytes. The MD5 output is returned as 16 bytes in a SSH_CMSG_AUTH_RSA_RESPONSE message. (MD5 is used to deter chosen plaintext attacks against RSA; the session id binds it to a specific session). + + The server verifies that the MD5 of the decrypted challenge returned by the client matches that of the original value, and sends SSH_SMSG_SUCCESS if so. Otherwise it sends SSH_SMSG_FAILURE and refuses the authentication attempt. + + This authentication method trusts the client side machine in that root on that machine can pretend to be any user on that machine. Additionally, it trusts the client host key. The name and/or IP address of the client host is only used to select the public host key. The same host name is used when scanning .rhosts or /etc/hosts.equiv and when selecting the host key. It would in principle be possible to eliminate the host name entirely and substitute it directly by the host key. IP and/or DNS [RFC1034] spoofing can only be used to pretend to be a host for which the attacker has the private host key. + + SSH_AUTH_RSA + + The idea behind RSA authentication is that the server recognizes the public key offered by the client, generates a random challenge, and encrypts the challenge with the public key. The client must then prove that it has the corresponding private key by decrypting the challenge. + + The client sends SSH_CMSG_AUTH_RSA with public key modulus (n) as an argument. + + The server may respond immediately with SSH_SMSG_FAILURE if it does not permit authentication with this key. Otherwise it generates a challenge, encrypts it using the user's public key (stored on the server and identified using the modulus), and sends SSH_SMSG_AUTH_RSA_CHALLENGE with the challenge (mp-int) as an argument. + + The challenge is 32 8-bit random bytes (256 bits). When encrypted, the highest (partial) byte is left as zero, the next byte contains the value 2, the following are non-zero random bytes, followed by a zero byte, and the challenge put in the remaining bytes. This is then encrypted with the public key. (The padding and encryption algorithm is the same as that used for the session key.) + + The client decrypts the challenge using its private key, concatenates it with the session id, and computes an MD5 checksum of the resulting 48 bytes. The MD5 output is returned as 16 bytes in a SSH_CMSG_AUTH_RSA_RESPONSE message. (Note that the MD5 is necessary to avoid chosen plaintext attacks against RSA; the session id binds it to a specific session.) + + The server verifies that the MD5 of the decrypted challenge returned by the client matches that of the original value, and sends SSH_SMSG_SUCCESS if so. Otherwise it sends SSH_SMSG_FAILURE and refuses the authentication attempt. + + This authentication method does not trust the remote host, the network, name services, or anything else. Authentication is based solely on the possession of the private identification keys. Anyone in possession of the private keys can log in, but nobody else. + + The server may have additional requirements for a successful authentiation. For example, to limit damage due to a compromised RSA key, a server might restrict access to a limited set of hosts. + + SSH_AUTH_PASSWORD + + The client sends a SSH_CMSG_AUTH_PASSWORD message with the plain text password. (Note that even though the password is plain text inside the message, it is normally encrypted by the packet mechanism.) + + The server verifies the password, and sends SSH_SMSG_SUCCESS if authentication was accepted and SSH_SMSG_FAILURE otherwise. + Note that the password is read from the user by the client; the user never interacts with a login program. + + This authentication method does not trust the remote host, the network, name services or anything else. Authentication is based solely on the possession of the password. Anyone in possession of the password can log in, but nobody else. + +Preparatory Operations + + After successful authentication, the server waits for a request from the client, processes the request, and responds with SSH_SMSG_SUCCESS whenever a request has been successfully processed. If it receives a message that it does not recognize or it fails to honor a request, it returns SSH_SMSG_FAILURE. It is expected that new message types might be added to this phase in future. + + The following messages are currently defined for this phase. + + SSH_CMSG_REQUEST_COMPRESSION + Requests that compression be enabled for this session. A gzipcompatible compression level (1-9) is passed as an argument. + + SSH_CMSG_REQUEST_PTY + Requests that a pseudo terminal device be allocated for this session. The user terminal type and terminal modes are supplied as arguments. + + SSH_CMSG_X11_REQUEST_FORWARDING + Requests forwarding of X11 connections from the remote machine to the local machine over the secure channel. Causes an internet-domain socket to be allocated and the DISPLAY variable to be set on the server. X11 authentication data is automatically passed to the server, and the client may implement spoofing of authentication data for added security. The authentication data is passed as arguments. + + SSH_CMSG_PORT_FORWARD_REQUEST + Requests forwarding of a TCP/IP port on the server host over the secure channel. What happens is that whenever a connection is made to the port on the server, a connection will be made from the client end to the specified host/port. Any user can forward unprivileged ports; only the root can forward privileged ports (as determined by authentication done earlier). + + SSH_CMSG_AGENT_REQUEST_FORWARDING + Requests forwarding of the connection to the authentication agent. + + SSH_CMSG_EXEC_SHELL + Starts a shell (command interpreter) for the user, and moves into interactive session mode. + + SSH_CMSG_EXEC_CMD + Executes the given command (actually " -c " or equivalent) for the user, and moves into interactive session mode. + + +Interactive Session and Exchange of Data + + During the interactive session, any data written by the shell or command running on the server machine is forwarded to stdin or stderr on the client machine, and any input available from stdin on the client machine is forwarded to the program on the server machine. + + All exchange is asynchronous; either side can send at any time, and there are no acknowledgements (TCP/IP already provides reliable transport, and the packet protocol protects against tampering or IP spoofing). + + When the client receives EOF from its standard input, it will send SSH_CMSG_EOF; however, this in no way terminates the exchange. The exchange terminates and interactive mode is left when the server sends SSH_SMSG_EXITSTATUS to indicate that the client program has terminated. Alternatively, either side may disconnect at any time by sending SSH_MSG_DISCONNECT or closing the connection. + + The server may send any of the following messages: + + SSH_SMSG_STDOUT_DATA + Data written to stdout by the program running on the server. + The data is passed as a string argument. The client writes this data to stdout. + + SSH_SMSG_STDERR_DATA + Data written to stderr by the program running on the server. + The data is passed as a string argument. The client writes this data to stderr. (Note that if the program is running on a tty, it is not possible to separate stdout and stderr data, and all data will be sent as stdout data.) + + SSH_SMSG_EXITSTATUS + Indicates that the shell or command has exited. Exit status is passed as an integer argument. This message causes termination of the interactive session. + + SSH_SMSG_AGENT_OPEN + Indicates that someone on the server side is requesting a connection to the authentication agent. The server-side channel number is passed as an argument. The client must respond with either SSH_CHANNEL_OPEN_CONFIRMATION or SSH_CHANNEL_OPEN_FAILURE. + + SSH_SMSG_X11_OPEN + Indicates that a connection has been made to the X11 socket on the server side and should be forwarded to the real X server. An integer argument indicates the channel number allocated for this connection on the server side. The client should send back either SSH_MSG_CHANNEL_OPEN_CONFIRMATION or SSH_MSG_CHANNEL_OPEN_FAILURE with the same server side channel number. + + SSH_MSG_PORT_OPEN + Indicates that a connection has been made to a port on the server side for which forwarding has been requested. Arguments are server side channel number, host name to connect to, and port to connect to. The client should send back either SSH_MSG_CHANNEL_OPEN_CONFIRMATION or SSH_MSG_CHANNEL_OPEN_FAILURE with the same server side channel number. + + SSH_MSG_CHANNEL_OPEN_CONFIRMATION + This is sent by the server to indicate that it has opened a connection as requested in a previous message. The first argument indicates the client side channel number, and the second argument is the channel number that the server has allocated for this connection. + + SSH_MSG_CHANNEL_OPEN_FAILURE + This is sent by the server to indicate that it failed to open a connection as requested in a previous message. The client-side channel number is passed as an argument. The client will close the descriptor associated with the channel and free the channel. + + SSH_MSG_CHANNEL_DATA + This packet contains data for a channel from the server. The + first argument is the client-side channel number, and the second + argument (a string) is the data. + + SSH_MSG_CHANNEL_CLOSE + This is sent by the server to indicate that whoever was in the + other end of the channel has closed it. The argument is the + client side channel number. The client will let all buffered + data in the channel to drain, and when ready, will close the + socket, free the channel, and send the server a + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION message for the channel. + + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + This is send by the server to indicate that a channel previously + closed by the client has now been closed on the server side as + well. The argument indicates the client channel number. The + client frees the channel. + + The client may send any of the following messages: + + SSH_CMSG_STDIN_DATA + This is data to be sent as input to the program running on the + server. The data is passed as a string. + + SSH_CMSG_EOF + Indicates that the client has encountered EOF while reading + standard input. The server will allow any buffered input data + to drain, and will then close the input to the program. + + SSH_CMSG_WINDOW_SIZE + Indicates that window size on the client has been changed. The + server updates the window size of the tty and causes SIGWINCH to + be sent to the program. The new window size is passed as four + integer arguments: row, col, xpixel, ypixel. + + SSH_MSG_PORT_OPEN + Indicates that a connection has been made to a port on the + client side for which forwarding has been requested. Arguments + are client side channel number, host name to connect to, and + port to connect to. The server should send back either + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE with the same client side channel + number. + + SSH_MSG_CHANNEL_OPEN_CONFIRMATION + This is sent by the client to indicate that it has opened a con- + nection as requested in a previous message. The first argument + indicates the server side channel number, and the second argu- + ment is the channel number that the client has allocated for + this connection. + + SSH_MSG_CHANNEL_OPEN_FAILURE + This is sent by the client to indicate that it failed to open a + connection as requested in a previous message. The server side + channel number is passed as an argument. The server will close + the descriptor associated with the channel and free the channel. + + SSH_MSG_CHANNEL_DATA + This packet contains data for a channel from the client. The + first argument is the server side channel number, and the second + argument (a string) is the data. + + SSH_MSG_CHANNEL_CLOSE + This is sent by the client to indicate that whoever was in the + other end of the channel has closed it. The argument is the + server channel number. The server will allow buffered data to + drain, and when ready, will close the socket, free the channel, + and send the client a SSH_MSG_CHANNEL_CLOSE_CONFIRMATION message + for the channel. + + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + This is send by the client to indicate that a channel previously + closed by the server has now been closed on the client side as + well. The argument indicates the server channel number. The + server frees the channel. + + Any unsupported messages during interactive mode cause the connection + to be terminated with SSH_MSG_DISCONNECT and an error message. Com- + patible protocol upgrades should agree about any extensions during + the preparation phase or earlier. + + +Termination of the Connection + + Normal termination of the connection is always initiated by the + server by sending SSH_SMSG_EXITSTATUS after the program has exited. + The client responds to this message by sending + SSH_CMSG_EXIT_CONFIRMATION and closes the socket; the server then + closes the socket. There are two purposes for the confirmation: some + systems may lose previously sent data when the socket is closed, and + closing the client side first causes any TCP/IP TIME_WAIT [RFC0793] + waits to occur on the client side, not consuming server resources. + + If the program terminates due to a signal, the server will send + SSH_MSG_DISCONNECT with an appropriate message. If the connection is + closed, all file descriptors to the program will be closed and the + server will exit. If the program runs on a tty, the kernel sends it + the SIGHUP signal when the pty master side is closed. + +Protocol Flags + + Both the server and the client pass 32 bits of protocol flags to the + other side. The flags are intended for compatible protocol exten- + sion; the server first announces which added capabilities it sup- + ports, and the client then sends the capabilities that it supports. + + The following flags are currently defined (the values are bit masks): + + 1 SSH_PROTOFLAG_SCREEN_NUMBER + This flag can only be sent by the client. It indicates that the + X11 forwarding requests it sends will include the screen number. + + 2 SSH_PROTOFLAG_HOST_IN_FWD_OPEN + If both sides specify this flag, SSH_SMSG_X11_OPEN and + SSH_MSG_PORT_OPEN messages will contain an additional field con- + taining a description of the host at the other end of the con- + nection. + +Detailed Description of Packet Types and Formats + + The supported packet types and the corresponding message numbers are + given in the following table. Messages with _MSG_ in their name may + be sent by either side. Messages with _CMSG_ are only sent by the + client, and messages with _SMSG_ only by the server. + + A packet may contain additional data after the arguments specified + below. Any such data should be ignored by the receiver. However, it + is recommended that no such data be stored without good reason. + (This helps build compatible extensions.) + + 0 SSH_MSG_NONE + This code is reserved. This message type is never sent. + + 1 SSH_MSG_DISCONNECT + + string Cause of disconnection + + This message may be sent by either party at any time. It causes + the immediate disconnection of the connection. The message is + intended to be displayed to a human, and describes the reason + for disconnection. + + 2 SSH_SMSG_PUBLIC_KEY + + 8 bytes anti_spoofing_cookie + 32-bit int server_key_bits + mp-int server_key_public_exponent + mp-int server_key_public_modulus + 32-bit int host_key_bits + mp-int host_key_public_exponent + mp-int host_key_public_modulus + 32-bit int protocol_flags + 32-bit int supported_ciphers_mask + 32-bit int supported_authentications_mask + + Sent as the first message by the server. This message gives the + server's host key, server key, protocol flags (intended for com- + patible protocol extension), supported_ciphers_mask (which is + the bitwise or of (1 << cipher_number), where << is the left + shift operator, for all supported ciphers), and + supported_authentications_mask (which is the bitwise or of (1 << + authentication_type) for all supported authentication types). + The anti_spoofing_cookie is 64 random bits, and must be sent + back verbatim by the client in its reply. It is used to make + IP-spoofing more difficult (encryption and host keys are the + real defense against spoofing). + + 3 SSH_CMSG_SESSION_KEY + + 1 byte cipher_type (must be one of the supported values) + 8 bytes anti_spoofing_cookie (must match data sent by the server) + mp-int double-encrypted session key + 32-bit int protocol_flags + + Sent by the client as the first message in the session. Selects + the cipher to use, and sends the encrypted session key to the + server. The anti_spoofing_cookie must be the same bytes that + were sent by the server. Protocol_flags is intended for nego- + tiating compatible protocol extensions. + + 4 SSH_CMSG_USER + + string user login name on server + + Sent by the client to begin authentication. Specifies the user + name on the server to log in as. The server responds with + SSH_SMSG_SUCCESS if no authentication is needed for this user, + or SSH_SMSG_FAILURE if authentication is needed (or the user + does not exist). [Note to the implementator: the user name is + of arbitrary size. The implementation must be careful not to + overflow internal buffers.] + + 5 SSH_CMSG_AUTH_RHOSTS + + string client-side user name + + Requests authentication using /etc/hosts.equiv and .rhosts (or + equivalent mechanisms). This authentication method is normally + disabled in the server because it is not secure (but this is the + method used by rsh and rlogin). The server responds with + SSH_SMSG_SUCCESS if authentication was successful, and + SSH_SMSG_FAILURE if access was not granted. The server should + check that the client side port number is less than 1024 (a + privileged port), and immediately reject authentication if it is + not. Supporting this authentication method is optional. This + method should normally not be enabled in the server because it + is not safe. (However, not enabling this only helps if rlogind + and rshd are disabled.) + + 6 SSH_CMSG_AUTH_RSA + + mp-int identity_public_modulus + + Requests authentication using pure RSA authentication. The + server checks if the given key is permitted to log in, and if + so, responds with SSH_SMSG_AUTH_RSA_CHALLENGE. Otherwise, it + responds with SSH_SMSG_FAILURE. The client often tries several + different keys in sequence until one supported by the server is + found. Authentication is accepted if the client gives the + correct response to the challenge. The server is free to add + other criteria for authentication, such as a requirement that + the connection must come from a certain host. Such additions + are not visible at the protocol level. Supporting this authen- + tication method is optional but recommended. + + 7 SSH_SMSG_AUTH_RSA_CHALLENGE + + mp-int encrypted challenge + + Presents an RSA authentication challenge to the client. The + challenge is a 256-bit random value encrypted as described else- + where in this document. The client must decrypt the challenge + using the RSA private key, compute MD5 of the challenge plus + session id, and send back the resulting 16 bytes using + SSH_CMSG_AUTH_RSA_RESPONSE. + + 8 SSH_CMSG_AUTH_RSA_RESPONSE + + 16 bytes MD5 of decrypted challenge + + This message is sent by the client in response to an RSA chal- + lenge. The MD5 checksum is returned instead of the decrypted + challenge to deter known-plaintext attacks against the RSA key. + The server responds to this message with either SSH_SMSG_SUCCESS + or SSH_SMSG_FAILURE. + + 9 SSH_CMSG_AUTH_PASSWORD + + string plain text password + + Requests password authentication using the given password. Note + that even though the password is plain text inside the packet, + the whole packet is normally encrypted by the packet layer. It + would not be possible for the client to perform password + encryption/hashing, because it cannot know which kind of + encryption/hashing, if any, the server uses. The server + responds to this message with SSH_SMSG_SUCCESS or + SSH_SMSG_FAILURE. + + 10 SSH_CMSG_REQUEST_PTY + + string TERM environment variable value (e.g. vt100) + 32-bit int terminal height, rows (e.g., 24) + 32-bit int terminal width, columns (e.g., 80) + 32-bit int terminal width, pixels (0 if no graphics) (e.g., 480) + 32-bit int terminal height, pixels (0 if no graphics) (e.g., 640) + n bytes tty modes encoded in binary + + Requests a pseudo-terminal to be allocated for this command. + This message can be used regardless of whether the session will + later execute the shell or a command. If a pty has been + requested with this message, the shell or command will run on a + pty. Otherwise it will communicate with the server using pipes, + sockets or some other similar mechanism. + + The terminal type gives the type of the user's terminal. In the + UNIX environment it is passed to the shell or command in the + TERM environment variable. + + The width and height values give the initial size of the user's + terminal or window. All values can be zero if not supported by + the operating system. The server will pass these values to the + kernel if supported. + + Terminal modes are encoded into a byte stream in a portable for- + mat. The exact format is described later in this document. + + The server responds to the request with either SSH_SMSG_SUCCESS + or SSH_SMSG_FAILURE. If the server does not have the concept of + pseudo terminals, it should return success if it is possible to + execute a shell or a command so that it looks to the client as + if it was running on a pseudo terminal. + + 11 SSH_CMSG_WINDOW_SIZE + + 32-bit int terminal height, rows + 32-bit int terminal width, columns + 32-bit int terminal width, pixels + 32-bit int terminal height, pixels + + This message can only be sent by the client during the interac- + tive session. This indicates that the size of the user's window + has changed, and provides the new size. The server will update + the kernel's notion of the window size, and a SIGWINCH signal or + equivalent will be sent to the shell or command (if supported by + the operating system). + + 12 SSH_CMSG_EXEC_SHELL + + (no arguments) + + Starts a shell (command interpreter), and enters interactive + session mode. + + 13 SSH_CMSG_EXEC_CMD + + string command to execute + + Starts executing the given command, and enters interactive ses- + sion mode. On UNIX, the command is run as " -c ", where is the user's login shell. + + 14 SSH_SMSG_SUCCESS + + (no arguments) + + This message is sent by the server in response to the session + key, a successful authentication request, and a successfully + completed preparatory operation. + + 15 SSH_SMSG_FAILURE + + (no arguments) + + This message is sent by the server in response to a failed + authentication operation to indicate that the user has not yet + been successfully authenticated, and in response to a failed + preparatory operation. This is also sent in response to an + authentication or preparatory operation request that is not + recognized or supported. + + 16 SSH_CMSG_STDIN_DATA + + string data + + Delivers data from the client to be supplied as input to the + shell or program running on the server side. This message can + only be used in the interactive session mode. No acknowledge- + ment is sent for this message. + + 17 SSH_SMSG_STDOUT_DATA + + string data + + Delivers data from the server that was read from the standard + output of the shell or program running on the server side. This + message can only be used in the interactive session mode. No + acknowledgement is sent for this message. + + 18 SSH_SMSG_STDERR_DATA + + string data + + Delivers data from the server that was read from the standard + error of the shell or program running on the server side. This + message can only be used in the interactive session mode. No + acknowledgement is sent for this message. + + 19 SSH_CMSG_EOF + + (no arguments) + + This message is sent by the client to indicate that EOF has been + reached on the input. Upon receiving this message, and after + all buffered input data has been sent to the shell or program, + the server will close the input file descriptor to the program. + This message can only be used in the interactive session mode. + No acknowledgement is sent for this message. + + 20 SSH_SMSG_EXITSTATUS + + 32-bit int exit status of the command + + Returns the exit status of the shell or program after it has + exited. The client should respond with + SSH_CMSG_EXIT_CONFIRMATION when it has received this message. + This will be the last message sent by the server. If the pro- + gram being executed dies with a signal instead of exiting nor- + mally, the server should terminate the session with + SSH_MSG_DISCONNECT (which can be used to pass a human-readable + string indicating that the program died due to a signal) instead + of using this message. + + 21 SSH_MSG_CHANNEL_OPEN_CONFIRMATION + + 32-bit int remote_channel + 32-bit int local_channel + + This is sent in response to any channel open request if the + channel has been successfully opened. Remote_channel is the + channel number received in the initial open request; + local_channel is the channel number the side sending this mes- + sage has allocated for the channel. Data can be transmitted on + the channel after this message. + + 22 SSH_MSG_CHANNEL_OPEN_FAILURE + + 32-bit int remote_channel + + This message indicates that an earlier channel open request by + the other side has failed or has been denied. Remote_channel is + the channel number given in the original request. + + 23 SSH_MSG_CHANNEL_DATA + + 32-bit int remote_channel + string data + + Data is transmitted in a channel in these messages. A channel + is bidirectional, and both sides can send these messages. There + is no acknowledgement for these messages. It is possible that + either side receives these messages after it has sent + SSH_MSG_CHANNEL_CLOSE for the channel. These messages cannot be + received after the party has sent or received + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION. + + 24 SSH_MSG_CHANNEL_CLOSE + + 32-bit int remote_channel + + When a channel is closed at one end of the connection, that side + sends this message. Upon receiving this message, the channel + should be closed. When this message is received, if the channel + is already closed (the receiving side has sent this message for + the same channel earlier), the channel is freed and no further + action is taken; otherwise the channel is freed and + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION is sent in response. (It is + possible that the channel is closed simultaneously at both + ends.) + + 25 SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + + 32-bit int remote_channel + + This message is sent in response to SSH_MSG_CHANNEL_CLOSE unless + the channel was already closed. When this message is sent or + received, the channel is freed. + + 26 (OBSOLETED; was unix-domain X11 forwarding) + + 27 SSH_SMSG_X11_OPEN + + 32-bit int local_channel + string originator_string (see below) + + This message can be sent by the server during the interactive + session mode to indicate that a client has connected the fake X + server. Local_channel is the channel number that the server has + allocated for the connection. The client should try to open a + connection to the real X server, and respond with + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE. + + The field originator_string is present if both sides specified + SSH_PROTOFLAG_HOST_IN_FWD_OPEN in the protocol flags. It con- + tains a description of the host originating the connection. + + 28 SSH_CMSG_PORT_FORWARD_REQUEST + + 32-bit int server_port + string host_to_connect + 32-bit int port_to_connect + + Sent by the client in the preparatory phase, this message + requests that server_port on the server machine be forwarded + over the secure channel to the client machine, and from there to + the specified host and port. The server should start listening + on the port, and send SSH_MSG_PORT_OPEN whenever a connection is + made to it. Supporting this message is optional, and the server + is free to reject any forward request. For example, it is + highly recommended that unless the user has been authenticated + as root, forwarding any privileged port numbers (below 1024) is + denied. + + 29 SSH_MSG_PORT_OPEN + + 32-bit int local_channel + string host_name + 32-bit int port + string originator_string (see below) + + Sent by either party in interactive session mode, this message + indicates that a connection has been opened to a forwarded + TCP/IP port. Local_channel is the channel number that the send- + ing party has allocated for the connection. Host_name is the + host the connection should be be forwarded to, and the port is + the port on that host to connect. The receiving party should + open the connection, and respond with + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE. It is recommended that the + receiving side check the host_name and port for validity to + avoid compromising local security by compromised remote side + software. Particularly, it is recommended that the client per- + mit connections only to those ports for which it has requested + forwarding with SSH_CMSG_PORT_FORWARD_REQUEST. + + The field originator_string is present if both sides specified + SSH_PROTOFLAG_HOST_IN_FWD_OPEN in the protocol flags. It con- + tains a description of the host originating the connection. + + 30 SSH_CMSG_AGENT_REQUEST_FORWARDING + + (no arguments) + + Requests that the connection to the authentication agent be for- + warded over the secure channel. The method used by clients to + contact the authentication agent within each machine is imple- + mentation and machine dependent. If the server accepts this + request, it should arrange that any clients run from this ses- + sion will actually contact the server program when they try to + contact the authentication agent. The server should then send a + SSH_SMSG_AGENT_OPEN to open a channel to the agent, and the + client should forward the connection to the real authentication + agent. Supporting this message is optional. + + 31 SSH_SMSG_AGENT_OPEN + + 32-bit int local_channel + + Sent by the server in interactive session mode, this message + requests opening a channel to the authentication agent. The + client should open a channel, and respond with either + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE. + + 32 SSH_MSG_IGNORE + + string data + + Either party may send this message at any time. This message, + and the argument string, is silently ignored. This message + might be used in some implementations to make traffic analysis + more difficult. This message is not currently sent by the + implementation, but all implementations are required to recog- + nize and ignore it. + + 33 SSH_CMSG_EXIT_CONFIRMATION + + (no arguments) + + Sent by the client in response to SSH_SMSG_EXITSTATUS. This is + the last message sent by the client. + + 34 SSH_CMSG_X11_REQUEST_FORWARDING + + string x11_authentication_protocol + string x11_authentication_data + 32-bit int screen number (if SSH_PROTOFLAG_SCREEN_NUMBER) + + Sent by the client during the preparatory phase, this message + requests that the server create a fake X11 display and set the + DISPLAY environment variable accordingly. An internet-domain + display is preferable. The given authentication protocol and + the associated data should be recorded by the server so that it + is used as authentication on connections (e.g., in .Xauthority). + The authentication protocol must be one of the supported X11 + authentication protocols, e.g., "MIT-MAGIC-COOKIE-1". Authenti- + cation data must be a lowercase hex string of even length. Its + interpretation is protocol dependent. The data is in a format + that can be used with e.g. the xauth program. Supporting this + message is optional. + + The client is permitted (and recommended) to generate fake + authentication information and send fake information to the + server. This way, a corrupt server will not have access to the + user's terminal after the connection has terminated. The + correct authorization codes will also not be left hanging around + in files on the server (many users keep the same X session for + months, thus protecting the authorization data becomes impor- + tant). + + X11 authentication spoofing works by initially sending fake + (random) authentication data to the server, and interpreting the + first packet sent by the X11 client after the connection has + been opened. The first packet contains the client's authentica- + tion. If the packet contains the correct fake data, it is + replaced by the client by the correct authentication data, and + then sent to the X server. + + 35 SSH_CMSG_AUTH_RHOSTS_RSA + + string clint-side user name + 32-bit int client_host_key_bits + mp-int client_host_key_public_exponent + mp-int client_host_key_public_modulus + + Requests authentication using /etc/hosts.equiv and .rhosts (or + equivalent) together with RSA host authentication. The server + should check that the client side port number is less than 1024 + (a privileged port), and immediately reject authentication if it + is not. The server responds with SSH_SMSG_FAILURE or + SSH_SMSG_AUTH_RSA_CHALLENGE. The client must respond to the + challenge with the proper SSH_CMSG_AUTH_RSA_RESPONSE. The + server then responds with success if access was granted, or + failure if the client gave a wrong response. Supporting this + authentication method is optional but recommended in most + environments. + + 36 SSH_MSG_DEBUG + + string debugging message sent to the other side + + This message may be sent by either party at any time. It is + used to send debugging messages that may be informative to the + user in solving various problems. For example, if authentica- + tion fails because of some configuration error (e.g., incorrect + permissions for some file), it can be very helpful for the user + to make the cause of failure available. On the other hand, one + should not make too much information available for security rea- + sons. It is recommended that the client provides an option to + display the debugging information sent by the sender (the user + probably does not want to see it by default). The server can + log debugging data sent by the client (if any). Either party is + free to ignore any received debugging data. Every implementa- + tion must be able to receive this message, but no implementation + is required to send these. + + 37 SSH_CMSG_REQUEST_COMPRESSION + + 32-bit int gzip compression level (1-9) + + This message can be sent by the client in the preparatory opera- + tions phase. The server responds with SSH_SMSG_FAILURE if it + does not support compression or does not want to compress; it + responds with SSH_SMSG_SUCCESS if it accepted the compression + request. In the latter case the response to this packet will + still be uncompressed, but all further packets in either direc- + tion will be compressed by gzip. + + 38 SSH_CMSG_MAX_PACKET_SIZE + + 32-bit int maximum packet size, bytes (4096-1024k) + + This message can be sent by the client in the preparatory opera- + tions phase. The server responds with SSH_SMSG_FAILURE if it + does not support limiting packet size, or with SSH_SMSG_SUCCESS + if it has limited the maximum packet size (as determined by the + value in the size field) to the specified value. + + 39 SSH_CMSG_AUTH_TIS + + (no arguments) + + This message starts TIS authentication. The server responds with + SSH_SMSG_FAILURE or SSH_SMSG_AUTH_TIS_CHALLENGE. + + 40 SSH_SMSG_AUTH_TIS_CHALLENGE + + string tis challenge + + Server sends TIS challenge to user and client should show it to + user and ask for response, which is sent back using + SSH_CMSG_AUTH_TIS_RESPONSE message. + + 41 SSH_CMSG_AUTH_TIS_RESPONSE + + string user response to tis challenge + + When client receives SSH_SMSG_AUTH_TIS_CHALLENGE and ask users + response to challenge it sends it back this message. The server + answers with SSH_SMSG_FAILURE or SSH_SMSG_SUCCESS. + + 42 SSH_CMSG_AUTH_KERBEROS + + string authentication info + + Client sends authentication info to server, which replies with + SSH_SMSG_AUTH_KERBEROS_RESPONSE message having correct response + data encrypted with the session key. + + 43 SSH_SMSG_AUTH_KERBEROS_RESPONSE + + string response data + + Server replies to SSH_CMSG_AUTH_KERBEROS message with this mes- + sage so that the response data is encrypted with session key. + + 44 SSH_CMSG_HAVE_KERBEROS_TGT + + string kerberos credentials + + Client sends kerberos credentials to server and the server + replies with SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE. + + +Encoding of Terminal Modes + + Terminal modes (as passed in SSH_CMSG_REQUEST_PTY) are encoded into a + byte stream. It is intended that the coding be portable across + different environments. + + The tty mode description is a stream of bytes. The stream consists + of opcode-argument pairs. It is terminated by opcode TTY_OP_END (0). + Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have 32-bit + integer arguments (stored msb first). Opcodes 160-255 are not yet + defined, and cause parsing to stop (they should only be used after + any other data). + + The client puts in the stream any modes it knows about, and the + server ignores any modes it does not know about. This allows some + degree of machine-independence, at least between systems that use a + POSIX-like [POSIX] tty interface. The protocol can support other + systems as well, but the client may need to fill reasonable values + for a number of parameters so the server pty gets set to a reasonable + mode (the server leaves all unspecified mode bits in their default + values, and only some combinations make sense). + + The following opcodes have been defined. The naming of opcodes + mostly follows the POSIX terminal mode flags. + + 0 TTY_OP_END + Indicates end of options. + + 1 VINTR + Interrupt character; 255 if none. Similarly for the other char- + acters. Not all of these characters are supported on all sys- + tems. + + 2 VQUIT + The quit character (sends SIGQUIT signal on UNIX systems). + + 3 VERASE + Erase the character to left of the cursor. + + 4 VKILL + Kill the current input line. + + 5 VEOF + End-of-file character (sends EOF from the terminal). + + 6 VEOL + End-of-line character in addition to carriage return and/or + linefeed. + + 7 VEOL2 + Additional end-of-line character. + + 8 VSTART + Continues paused output (normally ^Q). + + 9 VSTOP + Pauses output (^S). + + 10 VSUSP + Suspends the current program. + + 11 VDSUSP + Another suspend character. + + 12 VREPRINT + Reprints the current input line. + + 13 VWERASE + Erases a word left of cursor. + + 14 VLNEXT + More special input characters; these are probably not supported + on most systems. + + 15 VFLUSH + + 16 VSWTCH + + 17 VSTATUS + + 18 VDISCARD + + + 30 IGNPAR + The ignore parity flag. The next byte should be 0 if this flag + is not set, and 1 if it is set. + + 31 PARMRK + More flags. The exact definitions can be found in the POSIX + standard. + + 32 INPCK + + 33 ISTRIP + + 34 INLCR + + 35 IGNCR + + 36 ICRNL + + 37 IUCLC + + 38 IXON + + 39 IXANY + + 40 IXOFF + + 41 IMAXBEL + + + 50 ISIG + + 51 ICANON + + 52 XCASE + + 53 ECHO + + 54 ECHOE + + 55 ECHOK + + 56 ECHONL + + 57 NOFLSH + + 58 TOSTOP + + 59 IEXTEN + + 60 ECHOCTL + + 61 ECHOKE + + 62 PENDIN + + + 70 OPOST + + 71 OLCUC + + 72 ONLCR + + 73 OCRNL + + 74 ONOCR + + 75 ONLRET + + + 90 CS7 + + 91 CS8 + + 92 PARENB + + 93 PARODD + + + 192 TTY_OP_ISPEED + Specifies the input baud rate in bits per second (as a 32-bit + int, msb first). + + 193 TTY_OP_OSPEED + Specifies the output baud rate in bits per second (as a 32-bt + int, msb first). + + +The Authentication Agent Protocol + + The authentication agent is a program that can be used to hold RSA + authentication keys for the user (in future, it might hold data for + other authentication types as well). An authorized program can send + requests to the agent to generate a proper response to an RSA chal- + lenge. How the connection is made to the agent (or its representa- + tive) inside a host and how access control is done inside a host is + implementation-dependent; however, how it is forwarded and how one + interacts with it is specified in this protocol. The connection to + the agent is normally automatically forwarded over the secure chan- + nel. + + A program that wishes to use the agent first opens a connection to + its local representative (typically, the agent itself or an SSH + server). It then writes a request to the connection, and waits for + response. It is recommended that at least five minutes of timeout + are provided waiting for the agent to respond to an authentication + challenge (this gives sufficient time for the user to cut-and-paste + the challenge to a separate machine, perform the computation there, + and cut-and-paste the result back if so desired). + + Messages sent to and by the agent are in the following format: + + 4 bytes Length, msb first. Does not include length itself. + 1 byte Packet type. The value 255 is reserved for future extensions. + data Any data, depending on packet type. Encoding as in the ssh packet + protocol. + + + The following message types are currently defined: + + 1 SSH_AGENTC_REQUEST_RSA_IDENTITIES + + (no arguments) + + Requests the agent to send a list of all RSA keys for which it + can answer a challenge. + + 2 SSH_AGENT_RSA_IDENTITIES_ANSWER + + 32-bit int howmany + howmany times: + 32-bit int bits + mp-int public exponent + mp-int public modulus + string comment + + The agent sends this message in response to the to + SSH_AGENTC_REQUEST_RSA_IDENTITIES. The answer lists all RSA + keys for which the agent can answer a challenge. The comment + field is intended to help identify each key; it may be printed + by an application to indicate which key is being used. If the + agent is not holding any keys, howmany will be zero. + + 3 SSH_AGENTC_RSA_CHALLENGE + + 32-bit int bits + mp-int public exponent + mp-int public modulus + mp-int challenge + 16 bytes session_id + 32-bit int response_type + + Requests RSA decryption of random challenge to authenticate the + other side. The challenge will be decrypted with the RSA + private key corresponding to the given public key. + + The decrypted challenge must contain a zero in the highest (par- + tial) byte, 2 in the next byte, followed by non-zero random + bytes, a zero byte, and then the real challenge value in the + lowermost bytes. The real challenge must be 32 8-bit bytes (256 + bits). + + Response_type indicates the format of the response to be + returned. Currently the only supported value is 1, which means + to compute MD5 of the real challenge plus session id, and return + the resulting 16 bytes in a SSH_AGENT_RSA_RESPONSE message. + + 4 SSH_AGENT_RSA_RESPONSE + + 16 bytes MD5 of decrypted challenge + + Answers an RSA authentication challenge. The response is 16 + bytes: the MD5 checksum of the 32-byte challenge. + + 5 SSH_AGENT_FAILURE + + (no arguments) + + This message is sent whenever the agent fails to answer a + request properly. For example, if the agent cannot answer a + challenge (e.g., no longer has the proper key), it can respond + with this. The agent also responds with this message if it + receives a message it does not recognize. + + 6 SSH_AGENT_SUCCESS + + (no arguments) + + This message is sent by the agent as a response to certain + requests that do not otherwise cause a message be sent. + Currently, this is only sent in response to + SSH_AGENTC_ADD_RSA_IDENTITY and SSH_AGENTC_REMOVE_RSA_IDENTITY. + + 7 SSH_AGENTC_ADD_RSA_IDENTITY + + 32-bit int bits + mp-int public modulus + mp-int public exponent + mp-int private exponent + mp-int multiplicative inverse of p mod q + mp-int p + mp-int q + string comment + + Registers an RSA key with the agent. After this request, the + agent can use this RSA key to answer requests. The agent + responds with SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE. + + 8 SSH_AGENT_REMOVE_RSA_IDENTITY + + 32-bit int bits + mp-int public exponent + mp-int public modulus + + Removes an RSA key from the agent. The agent will no longer + accept challenges for this key and will not list it as a sup- + ported identity. The agent responds with SSH_AGENT_SUCCESS or + SSH_AGENT_FAILURE. + + If the agent receives a message that it does not understand, it + responds with SSH_AGENT_FAILURE. This permits compatible future + extensions. + + It is possible that several clients have a connection open to the + authentication agent simultaneously. Each client will use a separate + connection (thus, any SSH connection can have multiple agent connec- + tions active simultaneously). + + +References + + + [DES] FIPS PUB 46-1: Data Encryption Standard. National Bureau of + Standards, January 1988. FIPS PUB 81: DES Modes of Operation. + National Bureau of Standards, December 1980. Bruce Schneier: + Applied Cryptography. John Wiley & Sons, 1994. J. Seberry and + J. Pieprzyk: Cryptography: An Introduction to Computer Secu- + rity. Prentice-Hall, 1989. + + [GZIP] + The GNU GZIP program; available for anonymous ftp at + prep.ai.mit.edu. Please let me know if you know a paper + describing the algorithm. + + [IDEA] + Xuejia Lai: On the Design and Security of Block Ciphers, ETH + Series in Information Processing, vol. 1, Hartung-Gorre Verlag, + Konstanz, Switzerland, 1992. Bruce Schneier: Applied Cryptogra- + phy, John Wiley & Sons, 1994. See also the following patents: + PCT/CH91/00117, EP 0 482 154 B1, US Pat. 5,214,703. + + [PKCS#1] + PKCS #1: RSA Encryption Standard. Version 1.5, RSA Labora- + tories, November 1993. Available for anonymous ftp at + ftp.rsa.com. + + [POSIX] + Portable Operating System Interface (POSIX) - Part 1: Applica- + tion Program Interface (API) [C language], ISO/IEC 9945-1, IEEE + Std 1003.1, 1990. + + [RFC0791] + J. Postel: Internet Protocol, RFC 791, USC/ISI, September 1981. + + [RFC0793] + J. Postel: Transmission Control Protocol, RFC 793, USC/ISI, Sep- + tember 1981. + + [RFC1034] + P. Mockapetris: Domain Names - Concepts and Facilities, RFC + 1034, USC/ISI, November 1987. + + [RFC1282] + B. Kantor: BSD Rlogin, RFC 1258, UCSD, December 1991. + + [RSA] Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994. + See also R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic + Communications System and Method. US Patent 4,405,829, 1983. + + [X11] R. Scheifler: X Window System Protocol, X Consortium Standard, + Version 11, Release 6. Massachusetts Institute of Technology, + Laboratory of Computer Science, 1994. + + +Security Considerations + + This protocol deals with the very issue of user authentication and + security. + + First of all, as an implementation issue, the server program will + have to run as root (or equivalent) on the server machine. This is + because the server program will need be able to change to an arbi- + trary user id. The server must also be able to create a privileged + TCP/IP port. + + The client program will need to run as root if any variant of .rhosts + authentication is to be used. This is because the client program + will need to create a privileged port. The client host key is also + usually stored in a file which is readable by root only. The client + needs the host key in .rhosts authentication only. Root privileges + can be dropped as soon as the privileged port has been created and + the host key has been read. + + The SSH protocol offers major security advantages over existing tel- + net and rlogin protocols. + + o IP spoofing is restricted to closing a connection (by + encryption, host keys, and the special random cookie). If + encryption is not used, IP spoofing is possible for those who + can hear packets going out from the server. + + o DNS spoofing is made ineffective (by host keys). + + o Routing spoofing is made ineffective (by host keys). + + o All data is encrypted with strong algorithms to make eavesdrop- + ping as difficult as possible. This includes encrypting any + authentication information such as passwords. The information + for decrypting session keys is destroyed every hour. + + o Strong authentication methods: .rhosts combined with RSA host + authentication, and pure RSA authentication. + + o X11 connections and arbitrary TCP/IP ports can be forwarded + securely. + + o Man-in-the-middle attacks are deterred by using the server host + key to encrypt the session key. + + o Trojan horses to catch a password by routing manipulation are + deterred by checking that the host key of the server machine + matches that stored on the client host. + + The security of SSH against man-in-the-middle attacks and the secu- + rity of the new form of .rhosts authentication, as well as server + host validation, depends on the integrity of the host key and the + files containing known host keys. + + The host key is normally stored in a root-readable file. If the host + key is compromised, it permits attackers to use IP, DNS and routing + spoofing as with current rlogin and rsh. It should never be any + worse than the current situation. + + The files containing known host keys are not sensitive. However, if + an attacker gets to modify the known host key files, it has the same + consequences as a compromised host key, because the attacker can then + change the recorded host key. + + The security improvements obtained by this protocol for X11 are of + particular significance. Previously, there has been no way to pro- + tect data communicated between an X server and a client running on a + remote machine. By creating a fake display on the server, and for- + warding all X11 requests over the secure channel, SSH can be used to + run any X11 applications securely without any cooperation with the + vendors of the X server or the application. + + Finally, the security of this program relies on the strength of the + underlying cryptographic algorithms. The RSA algorithm is used for + authentication key exchange. It is widely believed to be secure. Of + the algorithms used to encrypt the session, DES has a rather small + key these days, probably permitting governments and organized crimi- + nals to break it in very short time with specialized hardware. 3DES + is probably safe (but slower). IDEA is widely believed to be secure. + People have varying degrees of confidence in the other algorithms. + This program is not secure if used with no encryption at all. + + +Additional Information + + Additional information (especially on the implementation and mailing + lists) is available via WWW at http://www.cs.hut.fi/ssh. + + Comments should be sent to Tatu Ylonen or the SSH + Mailing List . + +Author's Address + + + Tatu Ylonen + Helsinki University of Technology + Otakaari 1 + FIN-02150 Espoo, Finland + + Phone: +358-9-4354-3205 + Fax: +358-9-4354-3206 + EMail: ylo@cs.hut.fi + diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 00000000..77811828 --- /dev/null +++ b/doc/style.css @@ -0,0 +1,184 @@ + +body { +background-color:#ddf; +/*background-image:url(../back6.jpg);*/ +margin:10px 10px 10px 10px; +} + +h1 { +font-family:verdana, sans-serif; +font-size:80%; +color:black; +background-color:transparent; +text-align:left; +} +h2 { +font-family:verdana, sans-serif; +font-size:100%; +color:black; +background-color:transparent; +text-align:left; +} +h3 { +font-family:verdana, sans-serif; +font-size:80%; +color:black; +background-color:transparent; +text-align:left; +} +p { +font-family:verdana, sans-serif; +font-size:80%; +color:black; +background-color:transparent; +text-align:left; +margin-left:0px; +margin-right:0px; +} +li { +font-family:verdana, sans-serif; +font-size:80%; +color:black; +background-color:transparent; +text-align:left; +margin-left:0px; +margin-right:0px; +} +a:link { +font-family:verdana, sans-serif; +font-size:100%; +color:black; +background-color:transparent; +text-decoration:underline; +} +a:visited { +font-family:verdana, sans-serif; +font-size:100%; +color:black; +background-color:transparent; +text-decoration:underline; +} +a:hover { +font-family:verdana, sans-serif; +font-size:100%; +color:black; +background-color:transparent; +text-decoration:underline; +} + +table { +border-color:transparent; +border-style:solid; +border-width:1px; +} + +td { +font-family:verdana, sans-serif; +font-size:80%; +color:black; +text-align:left; +background-color:transparent; +border-color:transparent; +border-style:solid; +border-width:1px; +} + +.tout { + margin: 5px; + padding: 0px; + border: 2px solid #aac; + background: #eef; + } + +.prot { +border-style:solid; +border-width:2px; +border-color:#88F; +padding: 4px; +background-color:#cce; +margin: 5px 5px 5px 5px; +} + +.ex { +border-style:solid; +border-width:2px; +border-color:#aaF; +padding: 4px; +background-color:#dde; +margin: 5px 5px 5px 5px; +} +.desc { +border-style:solid; +border-width:3px; +border-color:#66F; +padding: 4px; +background-color:#aac; +margin: 15px 5px 20px 5px; +} + +#titre { + margin: 5px; + padding: 0px; + border: 5px solid #aac; + background: #eef; + } + +#gauche { + float:left; + margin: 5px; + padding: 4px; + border: 5px solid #aac; + background: #bbf; + width: 130px; + } + +#droite { + position: relative; + top:5px; + left:165px; + margin: 5px 170px 5px 5px; + padding: 10px; + border: 5px solid #aac; + background: #bbf; +} + +/* boutons */ + +a.bouton:link{ +width:128px; +height:34px; +text-decoration:none; +color:#aaa; +text-align:center; +font-weight:bold; +/*background-color:#444;*/ +background-image:url(noclicked.png); +} + +a.bouton:visited{ +width:128px; +height:34px; +text-decoration:none; +color:#aaa; +text-align:center; +font-weight:bold; +/*background-color:#444;*/ +background-image:url(noclicked.png); +} + +a.bouton:hover{ +width:128px; +height:34px; +text-decoration:none; +color:white; +text-align:center; +font-weight:bold; +/*background-color:#888;*/ +background-image:url(clicked.png); +} + +.bouton{ + text-align:center; +display:block; +} + diff --git a/include/libssh/config.h b/include/libssh/config.h new file mode 120000 index 00000000..bce5bfdd --- /dev/null +++ b/include/libssh/config.h @@ -0,0 +1 @@ +../../config.h \ No newline at end of file diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h new file mode 100644 index 00000000..3b8426cc --- /dev/null +++ b/include/libssh/crypto.h @@ -0,0 +1,47 @@ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* Crypto.h is an include file for internal structures of libssh */ +/* It hasn't to be into the final development set of files (and btw the filename would cause problems on most systems) */ +/* Openssl has (really) stupid defines */ +#ifdef set_key +#undef set_key +#endif +#ifdef cbc_encrypt +#undef cbc_encrypt +#endif +#ifdef cbc_decrypt +#undef cbc_decrypt +#endif +#ifdef des_set_key +#undef des_set_key +#endif +struct crypto_struct { + char *name; /* ssh name of the algorithm */ + unsigned int blocksize; /* blocksize of the algo */ + unsigned int keylen; /* length of the key structure */ + void *key; /* a key buffer allocated for the algo */ + unsigned int keysize; /* bytes of key used. != keylen */ + void (*set_encrypt_key)(struct crypto_struct *cipher, void *key); /* sets the new key for immediate use */ + void (*set_decrypt_key)(struct crypto_struct *cipher, void *key); + void (*cbc_encrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV); + void (*cbc_decrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV); +}; + diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h new file mode 100644 index 00000000..9e3495b8 --- /dev/null +++ b/include/libssh/libssh.h @@ -0,0 +1,234 @@ +/* +Copyright 2003,04 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#ifndef _LIBSSH_H +#define _LIBSSH_H +#include +#include +#include /* for fd_set * */ +#include +#define LIBSSH_VERSION "libssh-0.2-dev" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct string_struct STRING; +typedef struct buffer_struct BUFFER; +typedef struct public_key_struct PUBLIC_KEY; +typedef struct private_key_struct PRIVATE_KEY; +typedef struct ssh_options_struct SSH_OPTIONS; +typedef struct channel_struct CHANNEL; +typedef struct ssh_session SSH_SESSION; +typedef struct ssh_kbdint SSH_KBDINT; + +/* integer values */ +typedef u_int32_t u32; +typedef u_int16_t u16; +typedef u_int64_t u64; +typedef u_int8_t u8; + +/* the offsets of methods */ +#define SSH_KEX 0 +#define SSH_HOSTKEYS 1 +#define SSH_CRYPT_C_S 2 +#define SSH_CRYPT_S_C 3 +#define SSH_MAC_C_S 4 +#define SSH_MAC_S_C 5 +#define SSH_COMP_C_S 6 +#define SSH_COMP_S_C 7 +#define SSH_LANG_C_S 8 +#define SSH_LANG_S_C 9 + +#define SSH_CRYPT 2 +#define SSH_MAC 3 +#define SSH_COMP 4 +#define SSH_LANG 5 + +#define SSH_AUTH_SUCCESS 0 +#define SSH_AUTH_DENIED 1 +#define SSH_AUTH_PARTIAL 2 +#define SSH_AUTH_INFO 3 +#define SSH_AUTH_ERROR -1 + +/* status flags */ + +#define SSH_CLOSED (1<<0) +#define SSH_READ_PENDING (1<<1) +#define SSH_CLOSED_ERROR (1<<2) + +#define SSH_SERVER_ERROR -1 +#define SSH_SERVER_NOT_KNOWN 0 +#define SSH_SERVER_KNOWN_OK 1 +#define SSH_SERVER_KNOWN_CHANGED 2 +#define SSH_SERVER_FOUND_OTHER 3 + +#ifndef MD5_DIGEST_LEN + #define MD5_DIGEST_LEN 16 +#endif +/* errors */ + +#define SSH_NO_ERROR 0 +#define SSH_REQUEST_DENIED 1 +#define SSH_FATAL 2 +#define SSH_EINTR 3 + + +char *ssh_get_error(SSH_SESSION *session); +int ssh_get_error_code(SSH_SESSION *session); +void ssh_say(int priority,char *format,...); +void ssh_set_verbosity(int num); + + /* There is a verbosity level */ + /* 3 : packet level */ + /* 2 : protocol level */ + /* 1 : functions level */ + /* 0 : important messages only */ + /* -1 : no messages */ + +/* in client.c */ + +SSH_SESSION *ssh_new(); +void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options); +int ssh_connect(); +void ssh_disconnect(SSH_SESSION *session); +int ssh_service_request(SSH_SESSION *session,char *service); +char *ssh_get_issue_banner(SSH_SESSION *session); +/* get copyright informations */ +const char *ssh_copyright(); +/* string.h */ + +/* You can use these functions, they won't change */ +/* makestring returns a newly allocated string from a char * ptr */ +STRING *string_from_char(char *what); +/* it returns the string len in host byte orders. str->size is big endian warning ! */ +int string_len(STRING *str); +STRING *string_new(u32 size); +/* string_fill copies the data in the string. it does NOT check for boundary so allocate enough place with string_new */ +void string_fill(STRING *str,void *data,int len); +/* returns a newly allocated char array with the str string and a final nul caracter */ +char *string_to_char(STRING *str); +STRING *string_copy(STRING *str); +/* burns the data inside a string */ +void string_burn(STRING *str); + +/* deprecated */ +void ssh_crypto_init(); + +/* useful for debug */ +void ssh_print_hexa(char *descr,unsigned char *what, int len); +void ssh_get_random(void *,int); + +/* this one can be called by the client to see the hash of the public key before accepting it */ +int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]); +STRING *ssh_get_pubkey(SSH_SESSION *session); + +/* deprecated */ +int pubkey_get_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]); + +/* in connect.c */ +int ssh_fd_poll(SSH_SESSION *session); +int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout); + +void publickey_free(PUBLIC_KEY *key); + +/* in keyfiles.c */ + +PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,char *passphrase); +void private_key_free(PRIVATE_KEY *prv); +STRING *publickey_from_file(SSH_SESSION *session, char *filename,int *_type); +STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char **keys_path, + char **privkeyfile,int *type,int *count); +int ssh_is_server_known(SSH_SESSION *session); +int ssh_write_knownhost(SSH_SESSION *session); + +/* in channels.c */ + +CHANNEL *channel_new(SSH_SESSION *session); +int channel_open_forward(CHANNEL *channel,char *remotehost, int remoteport, char *sourcehost, int localport); +int channel_open_session(CHANNEL *channel); +void channel_free(CHANNEL *channel); +int channel_request_pty(CHANNEL *channel); +int channel_request_pty_size(CHANNEL *channel, char *term,int cols, int rows); +int channel_change_pty_size(CHANNEL *channel,int cols,int rows); +int channel_request_shell(CHANNEL *channel); +int channel_request_subsystem(CHANNEL *channel, char *system); +int channel_request_env(CHANNEL *channel,char *name, char *value); +int channel_request_exec(CHANNEL *channel, char *cmd); +int channel_request_sftp(CHANNEL *channel); +int channel_write(CHANNEL *channel,void *data,int len); +int channel_send_eof(CHANNEL *channel); +int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr); +int channel_poll(CHANNEL *channel, int is_stderr); +int channel_close(CHANNEL *channel); +int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr); +int channel_is_open(CHANNEL *channel); +/* in options.c */ + +SSH_OPTIONS *ssh_options_new(); +SSH_OPTIONS *ssh_options_copy(SSH_OPTIONS *opt); +int ssh_options_set_wanted_algos(SSH_OPTIONS *opt,int algo, char *list); +void ssh_options_set_username(SSH_OPTIONS *opt,char *username); +void ssh_options_set_port(SSH_OPTIONS *opt, unsigned int port); +int ssh_options_getopt(SSH_OPTIONS *options, int *argcptr, char **argv); +void ssh_options_set_host(SSH_OPTIONS *opt, const char *host); +void ssh_options_set_fd(SSH_OPTIONS *opt, int fd); +void ssh_options_set_bind(SSH_OPTIONS *opt, char *bindaddr,int port); +void ssh_options_set_identity(SSH_OPTIONS *opt, char *identity); +void ssh_options_set_status_callback(SSH_OPTIONS *opt, void (*callback) + (void *arg, float status), void *arg); +void ssh_options_set_timeout(SSH_OPTIONS *opt, long seconds, long usec); +void ssh_options_set_ssh_dir(SSH_OPTIONS *opt, char *dir); +void ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir); +void ssh_options_allow_ssh1(SSH_OPTIONS *opt, int allow); +void ssh_options_allow_ssh2(SSH_OPTIONS *opt, int allow); + + +/* buffer.c */ + +BUFFER *buffer_new(); +void buffer_free(BUFFER *buffer); +/* buffer_get returns a pointer to the begining of the buffer. no position is taken into account */ +void *buffer_get(BUFFER *buffer); +/* same here */ +int buffer_get_len(BUFFER *buffer); + + +/* in auth.c */ +/* these functions returns AUTH_ERROR is some serious error has happened, + AUTH_SUCCESS if success, + AUTH_PARTIAL if partial success, + AUTH_DENIED if refused */ +int ssh_userauth_none(SSH_SESSION *session,char *username); +int ssh_userauth_password(SSH_SESSION *session,char *username,char *password); +int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey); +int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey); +int ssh_userauth_autopubkey(SSH_SESSION *session); +int ssh_userauth_kbdint(SSH_SESSION *session, char *user, char *submethods); +int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session); +char *ssh_userauth_kbdint_getname(SSH_SESSION *session); +char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session); +char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i, char *echo); +void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer); + +#ifdef __cplusplus +} ; +#endif +#endif /* _LIBSSH_H */ diff --git a/include/libssh/priv.h b/include/libssh/priv.h new file mode 100644 index 00000000..5899fb6a --- /dev/null +++ b/include/libssh/priv.h @@ -0,0 +1,444 @@ +/* +Copyright 2003,04 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* priv.h file */ +/* This include file contains everything you shouldn't deal with in user programs. */ +/* Consider that anything in this file might change without notice; libssh.h file will keep */ +/* backward compatibility on binary & source */ + +#ifndef _LIBSSH_PRIV_H +#define _LIBSSH_PRIV_H +#include "libssh/libssh.h" + +/* Debugging constants */ + +/* Define this if you want to debug crypto systems */ +/* it's usefull when you are debugging the lib */ +/*#define DEBUG_CRYPTO */ + +/* some constants */ +#define MAX_PACKET_LEN 262144 +#define ERROR_BUFFERLEN 1024 +#define CLIENTBANNER1 "SSH-1.5-" LIBSSH_VERSION +#define CLIENTBANNER2 "SSH-2.0-" LIBSSH_VERSION +#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */ +/* some types for public keys */ +#define TYPE_DSS 1 +#define TYPE_RSA 2 +#define TYPE_RSA1 3 + +/* profiling constants. Don't touch them unless you know what you do */ +#define OPENSSL_CRYPTO +#define OPENSSL_BIGNUMS + + +#ifdef __cplusplus +extern "C" { +#endif + +/* wrapper things */ + +#ifdef OPENSSL_CRYPTO +#include +#include +#include +#include +#include +typedef SHA_CTX SHACTX; +typedef MD5_CTX MD5CTX; +typedef HMAC_CTX HMACCTX; +#ifdef MD5_DIGEST_LEN + #undef MD5_DIGEST_LEN +#endif +#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH +#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH + +#endif /* OPENSSL_CRYPTO */ +#ifdef OPENSSL_BIGNUMS +#include +typedef BIGNUM* bignum; +typedef BN_CTX* bignum_CTX; + +#define bignum_new() BN_new() +#define bignum_free(num) BN_clear_free(num) +#define bignum_set_word(bn,n) BN_set_word(bn,n) +#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data) +#define bignum_bn2hex(num) BN_bn2hex(num) +#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom) +#define bignum_ctx_new() BN_CTX_new() +#define bignum_ctx_free(num) BN_CTX_free(num) +#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx) +#define bignum_num_bytes(num) BN_num_bytes(num) +#define bignum_num_bits(num) BN_num_bits(num) +#define bignum_is_bit_set(num,bit) BN_is_bit_set(num,bit) +#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr) + +#endif /* OPENSSL_BIGNUMS */ +#ifdef HAVE_SYS_TIME_H +#include +#endif + +/* wrapper.c */ +MD5CTX *md5_init(void); +void md5_update(MD5CTX *c, const void *data, unsigned long len); +void md5_final(unsigned char *md,MD5CTX *c); +SHACTX *sha1_init(void); +void sha1_update(SHACTX *c, const void *data, unsigned long len); +void sha1_final(unsigned char *md,SHACTX *c); +void sha1(unsigned char *digest,int len,unsigned char *hash); +#define HMAC_SHA1 1 +#define HMAC_MD5 2 +HMACCTX *hmac_init(const void *key,int len,int type); +void hmac_update(HMACCTX *c, const void *data, unsigned long len); +void hmac_final(HMACCTX *ctx,unsigned char *hashmacbuf,int *len); + +/* strings and buffers */ +/* must be 32 bits number + immediatly our data */ +struct string_struct { + u32 size; + char string[MAX_PACKET_LEN]; +} __attribute__ ((packed)); + + +struct buffer_struct { + char *data; + int used; + int allocated; + int pos; +}; + +/* i should remove it one day */ +typedef struct packet_struct { + int valid; + u32 len; + u8 type; +} PACKET; + +typedef struct kex_struct { + char cookie[16]; + char **methods; +} KEX; + +struct public_key_struct { + int type; + char *type_c; /* Don't free it ! it is static */ + DSA *dsa_pub; + RSA *rsa_pub; +}; + +struct private_key_struct { + int type; + DSA *dsa_priv; + RSA *rsa_priv; +}; + +typedef struct signature_struct { + int type; + DSA_SIG *dsa_sign; + STRING *rsa_sign; +} SIGNATURE; + +struct ssh_options_struct { + char *banner; /* explicit banner to send */ + char *username; + char *host; + char *bindaddr; + int bindport; + char *identity; + char *ssh_dir; + char *known_hosts_file; + int fd; /* specificaly wanted file descriptor, don't connect host */ + int port; + int dont_verify_hostkey; /* Don't spare time, don't check host key ! unneeded to say it's dangerous and not safe */ + int use_nonexisting_algo; /* if user sets a not supported algorithm for kex, don't complain */ + char *wanted_methods[10]; /* the kex methods can be choosed. better use the kex fonctions to do that */ + void *wanted_cookie; /* wants a specific cookie to be sent ? if null, generate a new one */ + void *passphrase_function; /* this functions will be called if a keyphrase is needed. look keyfiles.c for more info */ + void (*connect_status_function)(void *arg, float status); /* status callback function */ + void *connect_status_arg; /* arbitrary argument */ + long timeout; /* seconds */ + long timeout_usec; + int ssh2allowed; + int ssh1allowed; +}; + +typedef struct ssh_crypto_struct { + bignum e,f,x,k; + char session_id[SHA_DIGEST_LEN]; + + char encryptIV[SHA_DIGEST_LEN*2]; + char decryptIV[SHA_DIGEST_LEN*2]; + + char decryptkey[SHA_DIGEST_LEN*2]; + char encryptkey[SHA_DIGEST_LEN*2]; + + char encryptMAC[SHA_DIGEST_LEN]; + char decryptMAC[SHA_DIGEST_LEN]; + char hmacbuf[EVP_MAX_MD_SIZE]; + struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */ + STRING *server_pubkey; + char *server_pubkey_type; + int do_compress_out; /* idem */ + int do_compress_in; /* don't set them, set the option instead */ + void *compress_out_ctx; /* don't touch it */ + void *compress_in_ctx; /* really, don't */ +} CRYPTO; + +struct channel_struct { + struct channel_struct *prev; + struct channel_struct *next; + SSH_SESSION *session; /* SSH_SESSION pointer */ + u32 local_channel; + u32 local_window; + int local_eof; + u32 local_maxpacket; + + u32 remote_channel; + u32 remote_window; + int remote_eof; /* end of file received */ + u32 remote_maxpacket; + int open; /* shows if the channel is still opened */ + int delayed_close; + BUFFER *stdout_buffer; + BUFFER *stderr_buffer; + void *userarg; + int version; + int blocking; +}; + +struct ssh_session { + int fd; + SSH_OPTIONS *options; + char *serverbanner; + char *clientbanner; + int protoversion; + u32 send_seq; + u32 recv_seq; +/* status flags */ + int closed; + int closed_by_except; + + int connected; + /* !=0 when the user got a session handle */ + int alive; + /* two previous are deprecated */ + int auth_service_asked; + +/* socket status */ + int data_to_read; /* reading now on socket will + not block */ + int data_to_write; + int data_except; + int blocking; // functions should not block + + STRING *banner; /* that's the issue banner from + the server */ + char *remotebanner; /* that's the SSH- banner from + remote host. */ + char *discon_msg; /* disconnect message from + the remote host */ + BUFFER *in_buffer; + PACKET in_packet; + BUFFER *out_buffer; + KEX server_kex; + KEX client_kex; + BUFFER *in_hashbuf; + BUFFER *out_hashbuf; + CRYPTO *current_crypto; + CRYPTO *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */ + + int channel_bytes_toread; /* left number of bytes + in the channel buffers + */ + CHANNEL *channels; /* linked list of channels */ + int maxchannel; + int exec_channel_opened; /* version 1 only. more + info in channels1.c */ + +/* error handling */ + int error_code; + char error_buffer[ERROR_BUFFERLEN]; +/* keyb interactive data */ + struct ssh_kbdint *kbdint; + int version; /* 1 or 2 */ +}; + +struct ssh_kbdint { + u32 nprompts; + char *name; + char *instruction; + char **prompts; + char *echo; /* bool array */ + char **answers; +}; +/* session.c */ + +void ssh_cleanup(SSH_SESSION *session); + + +/* errors.c */ +void ssh_set_error(SSH_SESSION *session,int code,char *descr,...); + +/* in dh.c */ +/* DH key generation */ +void dh_generate_e(SSH_SESSION *session); +void dh_generate_x(SSH_SESSION *session); +STRING *dh_get_e(SSH_SESSION *session); +void dh_import_f(SSH_SESSION *session,STRING *f_string); +void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string); +void dh_build_k(SSH_SESSION *session); +void make_sessionid(SSH_SESSION *session); +/* add data for the final cookie */ +void hashbufin_add_cookie(SSH_SESSION *session,unsigned char *cookie); +void hashbufout_add_cookie(SSH_SESSION *session); +void generate_session_keys(SSH_SESSION *session); +/* returns 1 if server signature ok, 0 otherwise. The NEXT crypto is checked, not the current one */ +int signature_verify(SSH_SESSION *session,STRING *signature); +bignum make_string_bn(STRING *string); +STRING *make_bignum_string(bignum num); + +/* in crypt.c */ +u32 packet_decrypt_len(SSH_SESSION *session,char *crypted); +int packet_decrypt(SSH_SESSION *session, void *packet,unsigned int len); +char *packet_encrypt(SSH_SESSION *session,void *packet,unsigned int len); + /* it returns the hmac buffer if exists*/ +int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,char *mac); + +/* in packet.c */ +void packet_clear_out(SSH_SESSION *session); +void packet_parse(SSH_SESSION *session); +int packet_send(SSH_SESSION *session); + +int packet_read(SSH_SESSION *session); +int packet_translate(SSH_SESSION *session); +int packet_wait(SSH_SESSION *session,int type,int blocking); + +/* connect.c */ +SSH_SESSION *ssh_session_new(); +int ssh_connect_host(SSH_SESSION *session, const char *host,const char + *bind_addr, int port, long timeout, long usec); + +/* in kex.c */ +extern char *ssh_kex_nums[]; +void send_kex(SSH_SESSION *session,int server_kex); +void list_kex(KEX *kex); +int set_kex(SSH_SESSION *session); +int ssh_get_kex(SSH_SESSION *session, int server_kex); +int verify_existing_algo(int algo,char *name); +char **space_tokenize(char *chain); +int ssh_get_kex1(SSH_SESSION *session); + +/* in keys.c */ +char *ssh_type_to_char(int type); +PUBLIC_KEY *publickey_make_dss(BUFFER *buffer); +PUBLIC_KEY *publickey_make_rsa(BUFFER *buffer,char *type); +PUBLIC_KEY *publickey_from_string(STRING *pubkey_s); +SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed_type); +void signature_free(SIGNATURE *sign); +STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, + PRIVATE_KEY *privatekey); +STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key); +/* channel.c */ +void channel_handle(SSH_SESSION *session, int type); +CHANNEL *channel_new(SSH_SESSION *session); +void channel_default_bufferize(CHANNEL *channel, void *data, int len, + int is_stderr); +/* options.c */ +void options_free(SSH_OPTIONS *opt); +/* this function must be called when no specific username has been asked. it has to guess it */ +int options_default_username(SSH_OPTIONS *opt); +int options_default_ssh_dir(SSH_OPTIONS *opt); +int options_default_known_hosts_file(SSH_OPTIONS *opt); + +/* buffer.c */ +void buffer_add_ssh_string(BUFFER *buffer,STRING *string); +void buffer_add_u8(BUFFER *buffer, u8 data); +void buffer_add_u32(BUFFER *buffer, u32 data); +void buffer_add_u64(BUFFER *buffer,u64 data); +void buffer_add_data(BUFFER *buffer, void *data, int len); +void buffer_add_data_begin(BUFFER *buffer,void *data,int len); +void buffer_add_buffer(BUFFER *buffer, BUFFER *source); +void buffer_reinit(BUFFER *buffer); + +/* buffer_get_rest returns a pointer to the current position into the buffer */ +void *buffer_get_rest(BUFFER *buffer); +/* buffer_get_rest_len returns the number of bytes which can be read */ +int buffer_get_rest_len(BUFFER *buffer); + +/* buffer_read_*() returns the number of bytes read, except for ssh strings */ +int buffer_get_u8(BUFFER *buffer,u8 *data); +int buffer_get_u32(BUFFER *buffer,u32 *data); +int buffer_get_u64(BUFFER *buffer, u64 *data); + +int buffer_get_data(BUFFER *buffer,void *data,int requestedlen); +/* buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */ +STRING *buffer_get_ssh_string(BUFFER *buffer); +/* gets a string out of a SSH-1 mpint */ +STRING *buffer_get_mpint(BUFFER *buffer); +/* buffer_pass_bytes acts as if len bytes have been read (used for padding) */ +int buffer_pass_bytes_end(BUFFER *buffer,int len); +int buffer_pass_bytes(BUFFER *buffer, int len); + +/* in base64.c */ +BUFFER *base64_to_bin(char *source); +char *bin_to_base64(unsigned char *source, int len); + +/* gzip.c */ +int compress_buffer(SSH_SESSION *session,BUFFER *buf); +int decompress_buffer(SSH_SESSION *session,BUFFER *buf); + +/* wrapper.c */ +int crypt_set_algorithms(SSH_SESSION *); +CRYPTO *crypto_new(); +void crypto_free(CRYPTO *crypto); +bignum bignum_new(); + +/* crc32.c */ +u32 ssh_crc32(char *buffer, int len); + +/* auth1.c */ +int ssh_userauth1_none(SSH_SESSION *session, char *username); +int ssh_userauth1_offer_pubkey(SSH_SESSION *session, char *username, + int type, STRING *pubkey); +int ssh_userauth1_password(SSH_SESSION *session, char *username, + char *password); +/* in misc.c */ +/* gets the user home dir. */ +char *ssh_get_user_home_dir(); +int ssh_file_readaccess_ok(char *file); + +/* macro for byte ordering */ +u64 ntohll(u64); +#define htonll(x) ntohll(x) + +/* channels1.c */ +CHANNEL *channel_open_session1(SSH_SESSION *session); +int channel_request_pty_size1(CHANNEL *channel, char *terminal,int cols, + int rows); +int channel_change_pty_size1(CHANNEL *channel, int cols, int rows); +int channel_request_shell1(CHANNEL *channel); +int channel_request_exec1(CHANNEL *channel, char *cmd); +void channel_handle1(SSH_SESSION *session,int type); +int channel_write1(CHANNEL *channel, void *data, int len); +#ifdef __cplusplus +} ; +#endif + +#endif /* _LIBSSH_PRIV_H */ diff --git a/include/libssh/server.h b/include/libssh/server.h new file mode 100644 index 00000000..90c280ee --- /dev/null +++ b/include/libssh/server.h @@ -0,0 +1,31 @@ +/* +Copyright 2004 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#ifndef SERVER_H +#define SERVER_H +/* the client banner doesn't say hey! look i'm a client ! */ +#include "libssh/libssh.h" +#define SERVERBANNER CLIENTBANNER + +int bind_socket(); +int listen_socket(int s); +int accept_socket(int s); + +#endif diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h new file mode 100644 index 00000000..22960e2c --- /dev/null +++ b/include/libssh/sftp.h @@ -0,0 +1,225 @@ +/* sftp headers */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#ifndef SFTP_H +#define SFTP_H +#include +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sftp_session_struct { + SSH_SESSION *session; + CHANNEL *channel; + int server_version; + struct request_queue *queue; + u32 id_counter; +} SFTP_SESSION ; + +typedef struct { + SFTP_SESSION *sftp; + u8 type; + BUFFER *payload; +} SFTP_PACKET; + +/* file handler */ +typedef struct sftp_file{ + SFTP_SESSION *sftp; + char *name; + u64 offset; + STRING *handle; + int eof; + int nonblocking; +} SFTP_FILE ; + +typedef struct sftp_dir { + SFTP_SESSION *sftp; + char *name; + STRING *handle; /* handle to directory */ + BUFFER *buffer; /* contains raw attributes from server which haven't been parsed */ + u32 count; /* counts the number of following attributes structures into buffer */ + int eof; /* end of directory listing */ +} SFTP_DIR; + +typedef struct { + SFTP_SESSION *sftp; + u8 packet_type; + BUFFER *payload; + u32 id; +} SFTP_MESSAGE; + +typedef struct request_queue{ + struct request_queue *next; + SFTP_MESSAGE *message; +} REQUEST_QUEUE; + +/* SSH_FXP_MESSAGE described into .7 page 26 */ +typedef struct { + u32 id; + u32 status; + STRING *error; + STRING *lang; + char *errormsg; + char *langmsg; +} STATUS_MESSAGE; + +/* don't worry much of these aren't really used */ +typedef struct { + char *name; + char *longname; /* some weird stuff */ + u32 flags; + u8 type; + u64 size; + u32 uid; + u32 gid; + char *owner; + char *group; + u32 permissions; + u64 atime64; + u32 atime; + u32 atime_nseconds; + u64 createtime; + u32 createtime_nseconds; + u64 mtime64; + u32 mtime; + u32 mtime_nseconds; + STRING *acl; + u32 extended_count; + STRING *extended_type; + STRING *extended_data; +} SFTP_ATTRIBUTES; + +#define LIBSFTP_VERSION 3 + +SFTP_SESSION *sftp_new(SSH_SESSION *session); +void sftp_free(SFTP_SESSION *sftp); +int sftp_init(SFTP_SESSION *sftp); +SFTP_DIR *sftp_opendir(SFTP_SESSION *session, char *path); +/* reads one file and attribute from opened directory. fails at end */ +SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir); +/* returns 1 if the directory was EOF */ +int sftp_dir_eof(SFTP_DIR *dir); +SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path); +SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path); +/* sftp_lstat stats a file but doesn't follow symlinks */ +SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file); +void sftp_attributes_free(SFTP_ATTRIBUTES *file); +int sftp_dir_close(SFTP_DIR *dir); +int sftp_file_close(SFTP_FILE *file); +/* access are the sames than the ones from ansi fopen() */ +SFTP_FILE *sftp_open(SFTP_SESSION *session, char *file, int access, SFTP_ATTRIBUTES *attr); +int sftp_read(SFTP_FILE *file, void *dest, int len); +int sftp_write(SFTP_FILE *file, void *source, int len); +void sftp_seek(SFTP_FILE *file, int new_offset); +unsigned long sftp_tell(SFTP_FILE *file); +void sftp_rewind(SFTP_FILE *file); +int sftp_rm(SFTP_SESSION *sftp, char *file); +int sftp_rmdir(SFTP_SESSION *sftp, char *directory); +int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr); +int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname); +int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr); +char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path); + +/* SFTP commands and constants */ +#define SSH_FXP_INIT 1 +#define SSH_FXP_VERSION 2 +#define SSH_FXP_OPEN 3 +#define SSH_FXP_CLOSE 4 +#define SSH_FXP_READ 5 +#define SSH_FXP_WRITE 6 +#define SSH_FXP_LSTAT 7 +#define SSH_FXP_FSTAT 8 +#define SSH_FXP_SETSTAT 9 +#define SSH_FXP_FSETSTAT 10 +#define SSH_FXP_OPENDIR 11 +#define SSH_FXP_READDIR 12 +#define SSH_FXP_REMOVE 13 +#define SSH_FXP_MKDIR 14 +#define SSH_FXP_RMDIR 15 +#define SSH_FXP_REALPATH 16 +#define SSH_FXP_STAT 17 +#define SSH_FXP_RENAME 18 +#define SSH_FXP_READLINK 19 +#define SSH_FXP_SYMLINK 20 + +#define SSH_FXP_STATUS 101 +#define SSH_FXP_HANDLE 102 +#define SSH_FXP_DATA 103 +#define SSH_FXP_NAME 104 +#define SSH_FXP_ATTRS 105 + +#define SSH_FXP_EXTENDED 200 +#define SSH_FXP_EXTENDED_REPLY 201 + +/* attributes */ +/* sftp draft is completely braindead : version 3 and 4 have different flags for same constants */ +/* and even worst, version 4 has same flag for 2 different constants */ +/* follow up : i won't develop any sftp4 compliant library before having a clarification */ + +#define SSH_FILEXFER_ATTR_SIZE 0x00000001 +#define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 +#define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 +#define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 +#define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 +#define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 +#define SSH_FILEXFER_ATTR_ACL 0x00000040 +#define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 +#define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100 +#define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 +#define SSH_FILEXFER_ATTR_UIDGID 0x00000002 + +/* types */ +#define SSH_FILEXFER_TYPE_REGULAR 1 +#define SSH_FILEXFER_TYPE_DIRECTORY 2 +#define SSH_FILEXFER_TYPE_SYMLINK 3 +#define SSH_FILEXFER_TYPE_SPECIAL 4 +#define SSH_FILEXFER_TYPE_UNKNOWN 5 + +/* server responses */ +#define SSH_FX_OK 0 +#define SSH_FX_EOF 1 +#define SSH_FX_NO_SUCH_FILE 2 +#define SSH_FX_PERMISSION_DENIED 3 +#define SSH_FX_FAILURE 4 +#define SSH_FX_BAD_MESSAGE 5 +#define SSH_FX_NO_CONNECTION 6 +#define SSH_FX_CONNECTION_LOST 7 +#define SSH_FX_OP_UNSUPPORTED 8 +#define SSH_FX_INVALID_HANDLE 9 +#define SSH_FX_NO_SUCH_PATH 10 +#define SSH_FX_FILE_ALREADY_EXISTS 11 +#define SSH_FX_WRITE_PROTECT 12 +#define SSH_FX_NO_MEDIA 13 + +/* file flags */ +#define SSH_FXF_READ 0x01 +#define SSH_FXF_WRITE 0x02 +#define SSH_FXF_APPEND 0x04 +#define SSH_FXF_CREAT 0x08 +#define SSH_FXF_TRUNC 0x10 +#define SSH_FXF_EXCL 0x20 +#define SSH_FXF_TEXT 0x40 + +#ifdef __cplusplus +} ; +#endif + +#endif /* SFTP_H */ diff --git a/include/libssh/ssh1.h b/include/libssh/ssh1.h new file mode 100644 index 00000000..ce67f20b --- /dev/null +++ b/include/libssh/ssh1.h @@ -0,0 +1,82 @@ +#ifndef __SSH1_H +#define __SSH1_H + +#define SSH_MSG_NONE 0 /* no message */ +#define SSH_MSG_DISCONNECT 1 /* cause (string) */ +#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */ +#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */ +#define SSH_CMSG_USER 4 /* user (string) */ +#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */ +#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */ +#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */ +#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */ +#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */ +#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */ +#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */ +#define SSH_CMSG_EXEC_SHELL 12 /* */ +#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */ +#define SSH_SMSG_SUCCESS 14 /* */ +#define SSH_SMSG_FAILURE 15 /* */ +#define SSH_CMSG_STDIN_DATA 16 /* data (string) */ +#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */ +#define SSH_SMSG_STDERR_DATA 18 /* data (string) */ +#define SSH_CMSG_EOF 19 /* */ +#define SSH_SMSG_EXITSTATUS 20 /* status (int) */ +#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */ +#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */ +#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */ +#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */ +#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */ +/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */ +#define SSH_SMSG_X11_OPEN 27 /* channel (int) */ +#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */ +#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */ +#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */ +#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */ +#define SSH_MSG_IGNORE 32 /* string */ +#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */ +#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */ +#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */ +#define SSH_MSG_DEBUG 36 /* string */ +#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */ +#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */ +#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */ +#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */ +#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */ +#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */ +#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */ +#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */ +#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */ + +/* protocol version 1.5 overloads some version 1.3 message types */ +#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE +#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + +/* + * Authentication methods. New types can be added, but old types should not + * be removed for compatibility. The maximum allowed value is 31. + */ +#define SSH_AUTH_RHOSTS 1 +#define SSH_AUTH_RSA 2 +#define SSH_AUTH_PASSWORD 3 +#define SSH_AUTH_RHOSTS_RSA 4 +#define SSH_AUTH_TIS 5 +#define SSH_AUTH_KERBEROS 6 +#define SSH_PASS_KERBEROS_TGT 7 + /* 8 to 15 are reserved */ +#define SSH_PASS_AFS_TOKEN 21 + +/* Protocol flags. These are bit masks. */ +#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */ +#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */ + +/* cipher flags. they are bit numbers */ +#define SSH_CIPHER_NONE 0 /* No encryption */ +#define SSH_CIPHER_IDEA 1 /* IDEA in CFB mode */ +#define SSH_CIPHER_DES 2 /* DES in CBC mode */ +#define SSH_CIPHER_3DES 3 /* Triple-DES in CBC mode */ +#define SSH_CIPHER_RC4 5 /* RC4 */ +#define SSH_CIPHER_BLOWFISH 6 + +#endif + diff --git a/include/libssh/ssh2.h b/include/libssh/ssh2.h new file mode 100644 index 00000000..e6dc04f5 --- /dev/null +++ b/include/libssh/ssh2.h @@ -0,0 +1,69 @@ +#ifndef __SSH2_H +#define __SSH2_H + +#define SSH2_MSG_DISCONNECT 1 +#define SSH2_MSG_IGNORE 2 +#define SSH2_MSG_UNIMPLEMENTED 3 +#define SSH2_MSG_DEBUG 4 +#define SSH2_MSG_SERVICE_REQUEST 5 +#define SSH2_MSG_SERVICE_ACCEPT 6 + +#define SSH2_MSG_KEXINIT 20 +#define SSH2_MSG_NEWKEYS 21 + +#define SSH2_MSG_KEXDH_INIT 30 +#define SSH2_MSG_KEXDH_REPLY 31 + +#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30 +#define SSH2_MSG_KEX_DH_GEX_GROUP 31 +#define SSH2_MSG_KEX_DH_GEX_INIT 32 +#define SSH2_MSG_KEX_DH_GEX_REPLY 33 +#define SSH2_MSG_KEX_DH_GEX_REQUEST 34 +#define SSH2_MSG_USERAUTH_REQUEST 50 +#define SSH2_MSG_USERAUTH_FAILURE 51 +#define SSH2_MSG_USERAUTH_SUCCESS 52 +#define SSH2_MSG_USERAUTH_BANNER 53 +#define SSH2_MSG_USERAUTH_PK_OK 60 +#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 +#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 +#define SSH2_MSG_GLOBAL_REQUEST 80 +#define SSH2_MSG_REQUEST_SUCCESS 81 +#define SSH2_MSG_REQUEST_FAILURE 82 +#define SSH2_MSG_CHANNEL_OPEN 90 +#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 +#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 +#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 +#define SSH2_MSG_CHANNEL_DATA 94 +#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 +#define SSH2_MSG_CHANNEL_EOF 96 +#define SSH2_MSG_CHANNEL_CLOSE 97 +#define SSH2_MSG_CHANNEL_REQUEST 98 +#define SSH2_MSG_CHANNEL_SUCCESS 99 +#define SSH2_MSG_CHANNEL_FAILURE 100 + +#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 +#define SSH2_DISCONNECT_PROTOCOL_ERROR 2 +#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 +#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 +#define SSH2_DISCONNECT_RESERVED 4 +#define SSH2_DISCONNECT_MAC_ERROR 5 +#define SSH2_DISCONNECT_COMPRESSION_ERROR 6 +#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 +#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 +#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 +#define SSH2_DISCONNECT_CONNECTION_LOST 10 +#define SSH2_DISCONNECT_BY_APPLICATION 11 +#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 +#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 +#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 +#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 + +#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 +#define SSH2_OPEN_CONNECT_FAILED 2 +#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 +#define SSH2_OPEN_RESOURCE_SHORTAGE 4 + +#define SSH2_EXTENDED_DATA_STDERR 1 + +#endif diff --git a/install-sh b/install-sh new file mode 100755 index 00000000..e9de2384 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/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 diff --git a/libssh.kdevelop b/libssh.kdevelop new file mode 100644 index 00000000..ed5d8f41 --- /dev/null +++ b/libssh.kdevelop @@ -0,0 +1,129 @@ + + + + Aris Adamantiadis (aka spacewalker) + aris@0xbadc0de.be + $VERSION$ + KDevAutoProject + C + + + + + src/libssh + debug + + + src/libssh + executable + + + + optimized + GccOptions + GppOptions + G77Options + -O2 -g0 + + + --enable-debug=full + debug + GccOptions + GppOptions + G77Options + -O0 -g3 + + + + + + + + + + + + libtool + + + + + ada + ada_bugs_gcc + bash + bash_bugs + clanlib + fortran_bugs_gcc + gnome1 + gnustep + gtk + gtk_bugs + haskell + haskell_bugs_ghc + java_bugs_gcc + java_bugs_sun + kde2book + libstdc++ + opengl + pascal_bugs_fp + php + php_bugs + perl + perl_bugs + python + python_bugs + qt-kdev3 + ruby + ruby_bugs + sdl + stl + sw + w3c-dom-level2-html + w3c-svg + w3c-uaag10 + wxwidgets_bugs + + + Guide to the Qt Translation Tools + Qt Assistant Manual + Qt Designer Manual + Qt Reference Documentation + qmake User Guide + + + KDE Libraries (Doxygen) + + + + + + + + + + + + + true + true + true + false + true + true + true + 250 + 400 + 250 + + + + + false + false + + + *.o,*.lo,CVS + false + + + diff --git a/libssh.kdevelop.pcs b/libssh.kdevelop.pcs new file mode 100644 index 00000000..81a14367 Binary files /dev/null and b/libssh.kdevelop.pcs differ diff --git a/libssh.kdevses b/libssh.kdevses new file mode 100644 index 00000000..b7db0959 --- /dev/null +++ b/libssh.kdevses @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libssh/Makefile.in b/libssh/Makefile.in new file mode 100644 index 00000000..ee6b5dd1 --- /dev/null +++ b/libssh/Makefile.in @@ -0,0 +1,44 @@ + +OBJECTS= client.o packet.o dh.o crypt.o connect.o error.o buffer.o \ + string.o kex.o channels.o options.o keys.o auth.o base64.o \ + keyfiles.o misc.o gzip.o wrapper.o sftp.o server.o crc32.o \ + session.o +SHELL = /bin/sh +VPATH = @srcdir@ + +subdirs = @subdirs@ +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +incldir= $(prefix)/include +infodir = $(prefix)/info +libdir = $(prefix)/lib/ +mandir = $(prefix)/man/man1 + +CC = @CC@ +CFLAGS = @CFLAGS@ -Wall -g -I../include/ -fPIC +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +INSTALL = @INSTALL@ +DYLIB_EXTENSION = @DYLIB_EXTENSION@ +LIBSSH_LDFLAGS = @LIBSSH_LDFLAGS@ + +all: libssh.so + +libssh.so: $(OBJECTS) + $(CC) -o libssh.$(DYLIB_EXTENSION) $(LIBSSH_LDFLAGS) $(OBJECTS) $(LIBS) $(LDFLAGS) +libssh.a: $(OBJECTS) + rm -f libssh.a + ar q libssh.a $(OBJECTS) + @RANLIB@ libssh.a +install: all + $(top_srcdir)/mkinstalldirs $(incldir) + $(top_srcdir)/mkinstalldirs $(libdir) + $(INSTALL) libssh.$(DYLIB_EXTENSION) $(libdir) +clean: + rm -f *~ libssh.a libssh.so *.o +distclean: clean + rm -f Makefile + diff --git a/libssh/auth.c b/libssh/auth.c new file mode 100644 index 00000000..9819ecd0 --- /dev/null +++ b/libssh/auth.c @@ -0,0 +1,605 @@ +/* auth.c deals with authentication methods */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "libssh/priv.h" +#include "libssh/ssh2.h" +#include +#include + +static int ask_userauth(SSH_SESSION *session){ + if(session->auth_service_asked) + return 0; + else { + if(ssh_service_request(session,"ssh-userauth")) + return -1; + else + session->auth_service_asked++; + } + return 0; + +} + +static void burn(char *ptr){ + if(ptr) + memset(ptr,'X',strlen(ptr)); +} + +static int wait_auth_status(SSH_SESSION *session,int kbdint){ + int err=SSH_AUTH_ERROR; + int cont=1; + STRING *can_continue; + u8 partial=0; + char *c_cont; + while(cont){ + if(packet_read(session)) + break; + if(packet_translate(session)) + break; + switch(session->in_packet.type){ + case SSH2_MSG_USERAUTH_FAILURE: + can_continue=buffer_get_ssh_string(session->in_buffer); + if(!can_continue || buffer_get_u8(session->in_buffer,&partial)!=1 ){ + ssh_set_error(session,SSH_FATAL, + "invalid SSH_MSG_USERAUTH_FAILURE message"); + return SSH_AUTH_ERROR; + } + c_cont=string_to_char(can_continue); + if(partial){ + err=SSH_AUTH_PARTIAL; + ssh_set_error(session,SSH_NO_ERROR,"partial success, authentications that can continue : %s",c_cont); + } + else { + err=SSH_AUTH_DENIED; + ssh_set_error(session,SSH_REQUEST_DENIED,"Access denied. authentications that can continue : %s",c_cont); + } + free(can_continue); + free(c_cont); + cont=0; + break; + case SSH2_MSG_USERAUTH_PK_OK: + /* SSH monkeys have defined the same number for both */ + /* SSH_MSG_USERAUTH_PK_OK and SSH_MSG_USERAUTH_INFO_REQUEST */ + /* which is not really smart; */ + /*case SSH2_MSG_USERAUTH_INFO_REQUEST: */ + if(kbdint){ + err=SSH_AUTH_INFO; + cont=0; + break; + } + /* continue through success */ + case SSH2_MSG_USERAUTH_SUCCESS: + err=SSH_AUTH_SUCCESS; + cont=0; + break; + case SSH2_MSG_USERAUTH_BANNER: + { + STRING *banner=buffer_get_ssh_string(session->in_buffer); + if(!banner){ + ssh_say(1,"The banner message was invalid. continuing though\n"); + break; + } + ssh_say(2,"Received a message banner\n"); + if(session->banner) + free(session->banner); /* erase the older one */ + session->banner=banner; + break; + } + default: + packet_parse(session); + break; + } + } + return err; +} + +/* use the "none" authentication question */ + +int ssh_userauth_none(SSH_SESSION *session,char *username){ + STRING *user; + STRING *service; + STRING *method; +#ifdef HAVE_SSH1 + if(session->version==1) + return ssh_userauth1_none(session,username); +#endif + if(!username) + if(!(username=session->options->username)){ + if(ssh_options_default_username(session->options)) + return SSH_AUTH_ERROR; + else + username=session->options->username; + } + if(ask_userauth(session)) + return SSH_AUTH_ERROR; + user=string_from_char(username); + method=string_from_char("none"); + service=string_from_char("ssh-connection"); + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); + buffer_add_ssh_string(session->out_buffer,user); + buffer_add_ssh_string(session->out_buffer,service); + buffer_add_ssh_string(session->out_buffer,method); + free(service); + free(method); + free(user); + packet_send(session); + return wait_auth_status(session,0); +} + +int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey){ + STRING *user; + STRING *service; + STRING *method; + STRING *algo; + int err=SSH_AUTH_ERROR; +#ifdef HAVE_SSH1 + if(session->version==1) + return ssh_userauth1_offer_pubkey(session,username,type,publickey); +#endif + if(!username) + if(!(username=session->options->username)){ + if(ssh_options_default_username(session->options)) + return SSH_AUTH_ERROR; + else + username=session->options->username; + } + if(ask_userauth(session)) + return SSH_AUTH_ERROR; + user=string_from_char(username); + service=string_from_char("ssh-connection"); + method=string_from_char("publickey"); + algo=string_from_char(ssh_type_to_char(type)); + + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); + buffer_add_ssh_string(session->out_buffer,user); + buffer_add_ssh_string(session->out_buffer,service); + buffer_add_ssh_string(session->out_buffer,method); + buffer_add_u8(session->out_buffer,0); + buffer_add_ssh_string(session->out_buffer,algo); + buffer_add_ssh_string(session->out_buffer,publickey); + packet_send(session); + err=wait_auth_status(session,0); + free(user); + free(method); + free(service); + free(algo); + return err; +} + +int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey){ + STRING *user; + STRING *service; + STRING *method; + STRING *algo; + STRING *sign; + int err=SSH_AUTH_ERROR; +// if(session->version==1) +// return ssh_userauth1_pubkey(session,username,publickey,privatekey); + if(!username) + if(!(username=session->options->username)){ + if(ssh_options_default_username(session->options)) + return err; + else + username=session->options->username; + } + if(ask_userauth(session)) + return err; + user=string_from_char(username); + service=string_from_char("ssh-connection"); + method=string_from_char("publickey"); + algo=string_from_char(ssh_type_to_char(privatekey->type)); + + + /* we said previously the public key was accepted */ + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); + buffer_add_ssh_string(session->out_buffer,user); + buffer_add_ssh_string(session->out_buffer,service); + buffer_add_ssh_string(session->out_buffer,method); + buffer_add_u8(session->out_buffer,1); + buffer_add_ssh_string(session->out_buffer,algo); + buffer_add_ssh_string(session->out_buffer,publickey); + sign=ssh_do_sign(session,session->out_buffer,privatekey); + if(sign){ + buffer_add_ssh_string(session->out_buffer,sign); + free(sign); + packet_send(session); + err=wait_auth_status(session,0); + } + free(user); + free(service); + free(method); + free(algo); + return err; +} + +int ssh_userauth_password(SSH_SESSION *session,char *username,char *password){ + STRING *user; + STRING *service; + STRING *method; + STRING *password_s; + int err; +#ifdef HAVE_SSH1 + if(session->version==1) + return ssh_userauth1_password(session,username,password); +#endif + if(!username) + if(!(username=session->options->username)){ + if(ssh_options_default_username(session->options)) + return SSH_AUTH_ERROR; + else + username=session->options->username; + } + if(ask_userauth(session)) + return SSH_AUTH_ERROR; + user=string_from_char(username); + service=string_from_char("ssh-connection"); + method=string_from_char("password"); + password_s=string_from_char(password); + + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); + buffer_add_ssh_string(session->out_buffer,user); + buffer_add_ssh_string(session->out_buffer,service); + buffer_add_ssh_string(session->out_buffer,method); + buffer_add_u8(session->out_buffer,0); + buffer_add_ssh_string(session->out_buffer,password_s); + free(user); + free(service); + free(method); + memset(password_s,0,strlen(password)+4); + free(password_s); + packet_send(session); + err=wait_auth_status(session,0); + return err; +} + +static char *keys_path[]={NULL,"%s/.ssh/identity","%s/.ssh/id_dsa","%s/.ssh/id_rsa",NULL}; +static char *pub_keys_path[]={NULL,"%s/.ssh/identity.pub","%s/.ssh/id_dsa.pub","%s/.ssh/id_rsa.pub",NULL}; + +/* this function initialy was in the client */ +/* but the fools are the ones who never change mind */ +int ssh_userauth_autopubkey(SSH_SESSION *session){ + int count=1; /* bypass identity */ + int type=0; + int err; + STRING *pubkey; + char *privkeyfile=NULL; + PRIVATE_KEY *privkey; + char *id=NULL; + // always testing none + err=ssh_userauth_none(session,NULL); + if(err==SSH_AUTH_ERROR || err==SSH_AUTH_SUCCESS){ + return err; + } + if(session->options->identity){ + ssh_say(2,"Trying identity file %s\n",session->options->identity); + keys_path[0]=session->options->identity; + /* let's hope alloca exists */ + id=malloc(strlen(session->options->identity)+1 + 4); + sprintf(id,"%s.pub",session->options->identity); + pub_keys_path[0]=id; + count =0; + } + while((pubkey=publickey_from_next_file(session,pub_keys_path,keys_path, &privkeyfile,&type,&count))){ + err=ssh_userauth_offer_pubkey(session,NULL,type,pubkey); + if(err==SSH_AUTH_ERROR){ + if(id){ + pub_keys_path[0]=NULL; + keys_path[0]=NULL; + free(id); + } + free(pubkey); + return err; + } else + if(err != SSH_AUTH_SUCCESS){ + ssh_say(2,"Public key refused by server\n"); + free(pubkey); + continue; + } + /* pubkey accepted by server ! */ + privkey=privatekey_from_file(session,privkeyfile,type,NULL); + if(!privkey){ + ssh_say(0,"Reading private key %s failed (bad passphrase ?)\n",privkeyfile); + free(pubkey); + continue; /* continue the loop with other pubkey */ + } + err=ssh_userauth_pubkey(session,NULL,pubkey,privkey); + if(err==SSH_AUTH_ERROR){ + if(id){ + pub_keys_path[0]=NULL; + keys_path[0]=NULL; + free(id); + } + free(pubkey); + private_key_free(privkey); + return err; + } else + if(err != SSH_AUTH_SUCCESS){ + ssh_say(0,"Weird : server accepted our public key but refused the signature\nit might be a bug of libssh\n"); + free(pubkey); + private_key_free(privkey); + continue; + } + /* auth success */ + ssh_say(1,"Authentication using %s success\n",privkeyfile); + free(pubkey); + private_key_free(privkey); + free(privkeyfile); + if(id){ + pub_keys_path[0]=NULL; + keys_path[0]=NULL; + free(id); + } + return SSH_AUTH_SUCCESS; + } + ssh_say(1,"Tried every public key, none matched\n"); + ssh_set_error(session,SSH_NO_ERROR,"no public key matched"); + if(id){ + pub_keys_path[0]=NULL; + keys_path[0]=NULL; + free(id); + } + + return SSH_AUTH_DENIED; +} + +static struct ssh_kbdint *kbdint_new(){ + struct ssh_kbdint *kbd=malloc(sizeof (struct ssh_kbdint)); + memset(kbd,0,sizeof(*kbd)); + return kbd; +} + + +static void kbdint_free(struct ssh_kbdint *kbd){ + int i,n=kbd->nprompts; + if(kbd->name) + free(kbd->name); + if(kbd->instruction) + free(kbd->instruction); + if(kbd->prompts){ + for(i=0;iprompts[i]); + free(kbd->prompts[i]); + } + free(kbd->prompts); + } + if(kbd->answers){ + for(i=0;ianswers[i]); + free(kbd->answers[i]); + } + free(kbd->answers); + } + if(kbd->echo){ + free(kbd->echo); + } + free(kbd); +} + +static void kbdint_clean(struct ssh_kbdint *kbd){ + int i,n=kbd->nprompts; + if(kbd->name){ + free(kbd->name); + kbd->name=NULL; + } + if(kbd->instruction){ + free(kbd->instruction); + kbd->instruction=NULL; + } + if(kbd->prompts){ + for(i=0;iprompts[i]); + free(kbd->prompts[i]); + } + free(kbd->prompts); + kbd->prompts=NULL; + } + if(kbd->answers){ + for(i=0;ianswers[i]); + free(kbd->answers[i]); + } + free(kbd->answers); + kbd->answers=NULL; + } + if(kbd->echo){ + free(kbd->echo); + kbd->echo=NULL; + } + kbd->nprompts=0; +} + +/* this function sends the first packet as explained in section 3.1 + * of the draft */ +static int kbdauth_init(SSH_SESSION *session, + char *user, char *submethods){ + STRING *user_s=string_from_char(user); + STRING *submethods_s=(submethods ? string_from_char(submethods): string_from_char("")); + STRING *service=string_from_char("ssh-connection"); + STRING *method=string_from_char("keyboard-interactive"); + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); + buffer_add_ssh_string(session->out_buffer,user_s); + buffer_add_ssh_string(session->out_buffer,service); + buffer_add_ssh_string(session->out_buffer,method); + buffer_add_u32(session->out_buffer,0); // language tag + buffer_add_ssh_string(session->out_buffer,submethods_s); + free(user_s); + free(service); + free(method); + free(submethods_s); + if(packet_send(session)) + return SSH_AUTH_ERROR; + return wait_auth_status(session,1); +} + +static int kbdauth_info_get(SSH_SESSION *session){ + STRING *name; /* name of the "asking" window showed to client */ + STRING *instruction; + STRING *tmp; + u32 nprompts; + int i; + name=buffer_get_ssh_string(session->in_buffer); + instruction=buffer_get_ssh_string(session->in_buffer); + tmp=buffer_get_ssh_string(session->in_buffer); + buffer_get_u32(session->in_buffer,&nprompts); + if(!name || !instruction || !tmp){ + if(name) + free(name); + if(instruction) + free(instruction); + // tmp must be empty if we got here + ssh_set_error(session,SSH_FATAL,"Invalid USERAUTH_INFO_REQUEST msg"); + return SSH_AUTH_ERROR; + } + if(tmp) + free(tmp); // no use + if(!session->kbdint) + session->kbdint=kbdint_new(); + else + kbdint_clean(session->kbdint); + session->kbdint->name=string_to_char(name); + free(name); + session->kbdint->instruction=string_to_char(instruction); + free(instruction); + nprompts=ntohl(nprompts); + if(nprompts>KBDINT_MAX_PROMPT){ + ssh_set_error(session,SSH_FATAL,"Too much prompt asked from server: %lu(0x%.8lx)",nprompts,nprompts); + return SSH_AUTH_ERROR; + } + session->kbdint->nprompts=nprompts; + session->kbdint->prompts=malloc(nprompts*sizeof(char *)); + memset(session->kbdint->prompts,0,nprompts*sizeof(char *)); + session->kbdint->echo=malloc(nprompts); + memset(session->kbdint->echo,0,nprompts); + for(i=0;iin_buffer); + buffer_get_u8(session->in_buffer,&session->kbdint->echo[i]); + if(!tmp){ + ssh_set_error(session,SSH_FATAL,"Short INFO_REQUEST packet"); + return SSH_AUTH_ERROR; + } + session->kbdint->prompts[i]=string_to_char(tmp); + free(tmp); + } + return SSH_AUTH_INFO; /* we are not auth. but we parsed the packet */ +} + +/* sends challenge back to the server */ +static int kbdauth_send(SSH_SESSION *session) { + STRING *answer; + int i; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_INFO_RESPONSE); + buffer_add_u32(session->out_buffer,htonl(session->kbdint->nprompts)); + for(i=0;ikbdint->nprompts;++i){ + if(session->kbdint->answers[i]) + answer=string_from_char(session->kbdint->answers[i]); + else + answer=string_from_char(""); + buffer_add_ssh_string(session->out_buffer,answer); + string_burn(answer); + free(answer); + } + if(packet_send(session)) + return SSH_AUTH_ERROR; + return wait_auth_status(session,1); +} + +/* the heart of the whole keyboard interactive login */ +int ssh_userauth_kbdint(SSH_SESSION *session,char *user,char *submethods){ + int err; + if(session->version==1) + return SSH_AUTH_DENIED; // no keyb-interactive for ssh1 + if( !session->kbdint){ + /* first time we call. we must ask for a challenge */ + if(!user) + if(!(user=session->options->username)){ + if(ssh_options_default_username(session->options)) + return SSH_AUTH_ERROR; + else + user=session->options->username; + } + if(ask_userauth(session)) + return SSH_AUTH_ERROR; + err=kbdauth_init(session,user,submethods); + if(err!=SSH_AUTH_INFO) + return err; /* error or first try success */ + err=kbdauth_info_get(session); + if(err==SSH_AUTH_ERROR){ + kbdint_free(session->kbdint); + session->kbdint=NULL; + } + return err; + } + /* if we are at this point, it's because session->kbdint exists */ + /* it means the user has set some informations there we need to send * + * the server. and then we need to ack the status (new questions or ok * + * pass in */ + err=kbdauth_send(session); + kbdint_free(session->kbdint); + session->kbdint=NULL; + if(err!=SSH_AUTH_INFO) + return err; + err=kbdauth_info_get(session); + if(err==SSH_AUTH_ERROR){ + kbdint_free(session->kbdint); + session->kbdint=NULL; + } + return err; +} + +int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session){ + return session->kbdint->nprompts; +} + +char *ssh_userauth_kbdint_getname(SSH_SESSION *session){ + return session->kbdint->name; +} + +char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session){ + return session->kbdint->instruction; +} + +char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i, + char *echo){ + if(i > session->kbdint->nprompts) + return NULL; + if(echo) + *echo=session->kbdint->echo[i]; + return session->kbdint->prompts[i]; +} + +void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer){ + if (i>session->kbdint->nprompts) + return; + if(!session->kbdint->answers){ + session->kbdint->answers=malloc(sizeof(char*)*session->kbdint->nprompts); + memset(session->kbdint->answers,0,sizeof(char *) * session->kbdint->nprompts); + } + if(session->kbdint->answers[i]){ + burn(session->kbdint->answers[i]); + free(session->kbdint->answers[i]); + } + session->kbdint->answers[i]=strdup(answer); +} diff --git a/libssh/base64.c b/libssh/base64.c new file mode 100644 index 00000000..849c2ca5 --- /dev/null +++ b/libssh/base64.c @@ -0,0 +1,210 @@ +/* base64 contains the needed support for base64 alphabet system, */ +/* as described in RFC1521 */ +/* +Copyright 2003,04 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* just the dirtiest part of code i ever made */ +#include +#include +#include +#include "libssh/priv.h" +static char alphabet[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/" ; + +/* transformations */ +#define SET_A(n,i) do { n |= (i&63) <<18; } while (0) +#define SET_B(n,i) do { n |= (i&63) <<12; } while (0) +#define SET_C(n,i) do { n |= (i&63) << 6; } while (0) +#define SET_D(n,i) do { n |= (i&63); } while (0) + +#define GET_A(n) ((n & 0xff0000) >> 16) +#define GET_B(n) ((n & 0xff00) >> 8) +#define GET_C(n) (n & 0xff) + +static int _base64_to_bin(unsigned char dest[3], char *source,int num); +static int get_equals(char *string); + +/* first part : base 64 to binary */ + +/* base64_to_bin translates a base64 string into a binary one. important, if something went wrong (ie incorrect char)*/ +/* it returns NULL */ +BUFFER *base64_to_bin(char *source){ + int len; + int equals; + BUFFER *buffer=buffer_new(); + unsigned char block[3]; + + /* get the number of equals signs, which mirrors the padding */ + equals=get_equals(source); + if(equals>2){ + buffer_free(buffer); + return NULL; + } + + len=strlen(source); + while(len>4){ + if(_base64_to_bin(block,source,3)){ + buffer_free(buffer); + return NULL; + } + buffer_add_data(buffer,block,3); + len-=4; + source+=4; + } + /* depending of the number of bytes resting, there are 3 possibilities (from the rfc) */ + switch(len){ +/* (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded output will be + an integral multiple of 4 characters with no "=" padding */ + case 4: + if(equals!=0){ + buffer_free(buffer); + return NULL; + } + if(_base64_to_bin(block,source,3)){ + buffer_free(buffer); + return NULL; + } + buffer_add_data(buffer,block,3); + return buffer; +/*(2) the final quantum of encoding input is exactly 8 bits; here, the final + unit of encoded output will be two characters followed by two "=" + padding characters */ + case 2: + if(equals!=2){ + buffer_free(buffer); + return NULL; + } + if(_base64_to_bin(block,source,1)){ + buffer_free(buffer); + return NULL; + } + buffer_add_data(buffer,block,1); + return buffer; +/* the final quantum of encoding input is + exactly 16 bits; here, the final unit of encoded output will be three + characters followed by one "=" padding character */ + case 3: + if(equals!=1){ + buffer_free(buffer); + return NULL; + } + if(_base64_to_bin(block,source,2)){ + buffer_free(buffer); + return NULL; + } + buffer_add_data(buffer,block,2); + return buffer; + default: + /* 4,3,2 are the only padding size allowed */ + buffer_free(buffer); + return NULL; + } + return NULL; +} + +#define BLOCK(letter,n) do { ptr=strchr(alphabet,source[n]);\ + if(!ptr) return -1;\ + i=ptr-alphabet;\ + SET_##letter(*block,i);\ + } while(0) +/* returns 0 if ok, -1 if not (ie invalid char into the stuff) */ +static int to_block4(unsigned long *block, char *source,int num){ + char *ptr; + unsigned int i; + *block=0; + if(num<1) + return 0; + BLOCK(A,0); /* 6 bits */ + BLOCK(B,1); /* 12 */ + if(num<2) + return 0; + BLOCK(C,2); /* 18 */ + if(num < 3) + return 0; + BLOCK(D,3); /* 24 */ + return 0; +} + +/* num = numbers of final bytes to be decoded */ +static int _base64_to_bin(unsigned char dest[3], char *source,int num){ + unsigned long block; + if(to_block4(&block,source,num)) + return -1; + dest[0]=GET_A(block); + dest[1]=GET_B(block); + dest[2]=GET_C(block); + return 0; +} + +/* counts the number of "=" signs, and replace them by zeroes */ +static int get_equals(char *string){ + char *ptr=string; + int num=0; + while((ptr=strchr(ptr,'='))){ + num++; + *ptr=0; + ptr++; + } + + return num; +} + +/* thanks sysk for debugging my mess :) */ +#define BITS(n) ((1<>2)]; + dest[1]=alphabet[((source[0] & BITS(2)) << 4)]; + dest[2]='='; + dest[3]='='; + break; + case 2: + dest[0]=alphabet[source[0]>>2]; + dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)]; + dest[2]=alphabet[(source[1]&BITS(4)) << 2]; + dest[3]='='; + break; + case 3: + dest[0]=alphabet[(source[0]>>2)]; + dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)]; + dest[2]=alphabet[ (source[2] >> 6) | (source[1]&BITS(4)) << 2]; + dest[3]=alphabet[source[2]&BITS(6)]; + break; + } +} + +char *bin_to_base64(unsigned char *source, int len){ + int flen=len + (3 - (len %3)); /* round to upper 3 multiple */ + char *buffer; + char *ptr; + flen=(4 * flen)/3 + 1 ; + ptr=buffer=malloc(flen); + while(len>0){ + _bin_to_base64(ptr,source,len>3?3:len); + ptr+=4; + source +=3; + len -=3; + } + ptr[0]=0; + return buffer; +} diff --git a/libssh/buffer.c b/libssh/buffer.c new file mode 100644 index 00000000..b511a8cd --- /dev/null +++ b/libssh/buffer.c @@ -0,0 +1,181 @@ +/* buffer.c */ +/* Well, buffers */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include +#include "libssh/priv.h" +BUFFER *buffer_new(){ + BUFFER *buffer=malloc(sizeof(BUFFER)); + memset(buffer,0,sizeof(BUFFER)); + return buffer; + } + +void buffer_free(BUFFER *buffer){ + if(buffer->data){ + memset(buffer->data,0,buffer->allocated); /* burn the data */ + free(buffer->data); + } + free(buffer); + } + +void buffer_reinit(BUFFER *buffer){ + memset(buffer->data,0,buffer->used); + buffer->used=0; + buffer->pos=0; +} + +static void realloc_buffer(BUFFER *buffer,int needed){ + needed=(needed+0x7f) & ~0x7f; + buffer->data=realloc(buffer->data,needed); + buffer->allocated=needed; +} + +void buffer_add_data(BUFFER *buffer,void *data,int len){ + if(buffer->allocated < buffer->used+len) + realloc_buffer(buffer,buffer->used+len); + memcpy(buffer->data+buffer->used,data,len); + buffer->used+=len; + } + +void buffer_add_ssh_string(BUFFER *buffer,STRING *string){ + u32 len=ntohl(string->size); + buffer_add_data(buffer,string,len+sizeof(u32)); + } + +void buffer_add_u32(BUFFER *buffer,u32 data){ + buffer_add_data(buffer,&data,sizeof(data)); +} + +void buffer_add_u64(BUFFER *buffer,u64 data){ + buffer_add_data(buffer,&data,sizeof(data)); +} + +void buffer_add_u8(BUFFER *buffer,u8 data){ + buffer_add_data(buffer,&data,sizeof(u8)); +} + +void buffer_add_data_begin(BUFFER *buffer, void *data, int len){ + if(buffer->allocated < buffer->used + len) + realloc_buffer(buffer,buffer->used+len); + memmove(buffer->data+len,buffer->data,buffer->used); + memcpy(buffer->data,data,len); + buffer->used+=len; +} + +void buffer_add_buffer(BUFFER *buffer, BUFFER *source){ + buffer_add_data(buffer,buffer_get(source),buffer_get_len(source)); +} + +void *buffer_get(BUFFER *buffer){ + return buffer->data; +} + +void *buffer_get_rest(BUFFER *buffer){ + return buffer->data+buffer->pos; +} + +int buffer_get_len(BUFFER *buffer){ + return buffer->used; +} + +int buffer_get_rest_len(BUFFER *buffer){ + return buffer->used - buffer->pos; +} + +int buffer_pass_bytes(BUFFER *buffer,int len){ + if(buffer->used < buffer->pos+len) + return 0; + buffer->pos+=len; + /* if the buffer is empty after having passed the whole bytes into it, we can clean it */ + if(buffer->pos==buffer->used){ + buffer->pos=0; + buffer->used=0; + } + return len; +} + +int buffer_pass_bytes_end(BUFFER *buffer,int len){ + if(buffer->used < buffer->pos + len) + return 0; + buffer->used-=len; + return len; +} + +int buffer_get_data(BUFFER *buffer, void *data, int len){ + if(buffer->pos+len>buffer->used) + return 0; /*no enough data in buffer */ + memcpy(data,buffer->data+buffer->pos,len); + buffer->pos+=len; + return len; /* no yet support for partial reads (is it really needed ?? ) */ +} + +int buffer_get_u8(BUFFER *buffer, u8 *data){ + return buffer_get_data(buffer,data,sizeof(u8)); +} + +int buffer_get_u32(BUFFER *buffer, u32 *data){ + return buffer_get_data(buffer,data,sizeof(u32)); +} + +int buffer_get_u64(BUFFER *buffer, u64 *data){ + return buffer_get_data(buffer,data,sizeof(u64)); +} + +STRING *buffer_get_ssh_string(BUFFER *buffer){ + u32 stringlen; + u32 hostlen; + STRING *str; + if(buffer_get_u32(buffer,&stringlen)==0) + return NULL; + hostlen=ntohl(stringlen); + /* verify if there is enough space in buffer to get it */ + if(buffer->pos+hostlen>buffer->used) + return 0; /* it is indeed */ + str=string_new(hostlen); + if(buffer_get_data(buffer,str->string,hostlen)!=hostlen){ + ssh_say(0,"buffer_get_ssh_string: oddish : second test failed when first was successful. len=%d",hostlen); + free(str); + return NULL; + } + return str; +} + +/* this one is SSH-1 only */ +STRING *buffer_get_mpint(BUFFER *buffer){ + u16 bits; + u32 len; + STRING *str; + if(buffer_get_data(buffer,&bits,sizeof(u16))!= sizeof(u16)) + return NULL; + bits=ntohs(bits); + len=(bits+7)/8; + if(buffer->pos+len > buffer->used) + return NULL; + str=string_new(len); + if(buffer_get_data(buffer,str->string,len)!=len){ + free(str); + return NULL; + } + return str; +} + diff --git a/libssh/channels.c b/libssh/channels.c new file mode 100644 index 00000000..04eeaa99 --- /dev/null +++ b/libssh/channels.c @@ -0,0 +1,701 @@ +/* channels.c */ +/* It has support for ... ssh channels */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include + +#include "libssh/priv.h" +#include "libssh/ssh2.h" +#define WINDOWLIMIT 1024 +#define WINDOWBASE 32000 + +CHANNEL *channel_new(SSH_SESSION *session){ + CHANNEL *channel=malloc(sizeof(CHANNEL)); + memset(channel,0,sizeof(CHANNEL)); + channel->session=session; + channel->version=session->version; + channel->stdout_buffer=buffer_new(); + channel->stderr_buffer=buffer_new(); + if(!session->channels){ + session->channels=channel; + channel->next=channel->prev=channel; + return channel; + } + channel->next=session->channels; + channel->prev=session->channels->prev; + channel->next->prev=channel; + channel->prev->next=channel; + return channel; +} + +static u32 channel_new_id(SSH_SESSION *session){ + u32 ret=session->maxchannel; + session->maxchannel++; + return ret; +} + +static int channel_open(CHANNEL *channel,char *type_c,int window, +int maxpacket,BUFFER *payload){ + SSH_SESSION *session=channel->session; + STRING *type=string_from_char(type_c); + u32 foo; + int err; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN); + channel->local_channel=channel_new_id(session); + channel->local_maxpacket=maxpacket; + channel->local_window=window; + ssh_say(2,"creating a channel %d with %d window and %d max packet\n", + channel->local_channel, window,maxpacket); + buffer_add_ssh_string(session->out_buffer,type); + buffer_add_u32(session->out_buffer,htonl(channel->local_channel)); + buffer_add_u32(session->out_buffer,htonl(channel->local_window)); + buffer_add_u32(session->out_buffer,htonl(channel->local_maxpacket)); + free(type); + if(payload) + buffer_add_buffer(session->out_buffer,payload); + packet_send(session); + ssh_say(2,"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d\n",type_c,channel->local_channel); + err=packet_wait(session,SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,1); + switch(session->in_packet.type){ + case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: + buffer_get_u32(session->in_buffer,&foo); + if(channel->local_channel!=ntohl(foo)){ + ssh_set_error(session,SSH_FATAL,"server answered with sender chan num %d instead of given %d", + ntohl(foo),channel->local_channel); + return -1; + } + buffer_get_u32(session->in_buffer,&foo); + channel->remote_channel=ntohl(foo); + buffer_get_u32(session->in_buffer,&foo); + channel->remote_window=ntohl(foo); + buffer_get_u32(session->in_buffer,&foo); + channel->remote_maxpacket=ntohl(foo); + ssh_say(3,"Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d\n" + ,channel->local_channel,channel->remote_channel); + ssh_say(3,"Remote window : %ld, maxpacket : %ld\n", + channel->remote_window, channel->remote_maxpacket); + channel->open=1; + return 0; + case SSH2_MSG_CHANNEL_OPEN_FAILURE: + { + u32 code; + STRING *error_s; + char *error; + buffer_get_u32(session->in_buffer,&foo); + buffer_get_u32(session->in_buffer,&code); + error_s=buffer_get_ssh_string(session->in_buffer); + error=string_to_char(error_s); + ssh_set_error(session,SSH_REQUEST_DENIED,"Channel opening failure : channel %d error (%d) %s", + channel->local_channel,ntohl(code),error); + free(error); + free(error_s); + return -1; + } + default: + ssh_set_error(session,SSH_FATAL,"Received unknown packet %d\n",session->in_packet.type); + return -1; + } + return -1; +} + +static CHANNEL *find_local_channel(SSH_SESSION *session,u32 num){ + // we assume we are always the local + CHANNEL *initchan,*channel; + initchan=session->channels; + if(!initchan) + return NULL; + for(channel=initchan;channel->local_channel!=num;channel=channel->next){ + if(channel->next==initchan) + return NULL; + } + return channel; +} + +static void grow_window(SSH_SESSION *session, CHANNEL *channel){ + u32 new_window=WINDOWBASE; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_WINDOW_ADJUST); + buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)); + buffer_add_u32(session->out_buffer,htonl(new_window)); + packet_send(session); + ssh_say(3,"growing window (channel %d:%d) to %d bytes\n", + channel->local_channel,channel->remote_channel, + channel->local_window + new_window); + channel->local_window+=new_window; +} + +static CHANNEL *channel_from_msg(SSH_SESSION *session){ + u32 chan; + CHANNEL *channel; + if (buffer_get_u32(session->in_buffer,&chan)!=sizeof(u32)){ + ssh_set_error(session,SSH_FATAL,"Getting channel from message : short read"); + return NULL; + } + channel=find_local_channel(session,ntohl(chan)); + if(!channel) + ssh_set_error(session,SSH_FATAL,"Server specified invalid channel %d",ntohl(chan)); + return channel; +} + +static void channel_rcv_change_window(SSH_SESSION *session){ + u32 bytes; + CHANNEL *channel; + int err; + channel=channel_from_msg(session); + if(!channel) + ssh_say(0,"%s\n",ssh_get_error(session)); + err = buffer_get_u32(session->in_buffer,&bytes); + if(!channel || err!= sizeof(u32)){ + ssh_say(1,"Error getting a window adjust message : invalid packet\n"); + return; + } + bytes=ntohl(bytes); + ssh_say(3,"Adding %d bytes to channel (%d:%d) (from %d bytes)\n",bytes, + channel->local_channel,channel->remote_channel,channel->remote_window); + channel->remote_window+=bytes; +} + +/* is_stderr is set to 1 if the data are extended, ie stderr */ +static void channel_rcv_data(SSH_SESSION *session,int is_stderr){ + STRING *str; + CHANNEL *channel; + channel=channel_from_msg(session); + if(!channel){ + ssh_say(0,"%s",ssh_get_error(session)); + return; + } + if(is_stderr){ + u32 ignore; + /* uint32 data type code. we can ignore it */ + buffer_get_u32(session->in_buffer,&ignore); + } + str=buffer_get_ssh_string(session->in_buffer); + + if(!str){ + ssh_say(0,"Invalid data packet !\n"); + return; + } + ssh_say(3,"adding %d bytes data in %d\n",string_len(str),is_stderr); + /* what shall we do in this case ? let's accept it anyway */ + if(string_len(str)>channel->local_window) + ssh_say(0,"Data packet too big for our window(%d vs %d)",string_len(str),channel->local_window); + channel_default_bufferize(channel,str->string,string_len(str), is_stderr); + if(string_len(str)>=channel->local_window) + channel->local_window-=string_len(str); + else + channel->local_window=0; /* buggy remote */ + if(channel->local_window < WINDOWLIMIT) + grow_window(session,channel); /* i wonder if this is the correct place to do that */ + free(str); +} + +static void channel_rcv_eof(SSH_SESSION *session){ + CHANNEL *channel; + channel=channel_from_msg(session); + if(!channel){ + ssh_say(0,"%s\n",ssh_get_error(session)); + return; + } + ssh_say(2,"Received eof on channel (%d:%d)\n",channel->local_channel, + channel->remote_channel); +// channel->remote_window=0; + channel->remote_eof=1; +} + +static void channel_rcv_close(SSH_SESSION *session){ + CHANNEL *channel; + channel=channel_from_msg(session); + if(!channel){ + ssh_say(0,"%s\n",ssh_get_error(session)); + return; + } + ssh_say(2,"Received close on channel (%d:%d)\n",channel->local_channel, + channel->remote_channel); + if((channel->stdout_buffer && buffer_get_rest_len(channel->stdout_buffer)>0) + || (channel->stderr_buffer && buffer_get_rest_len(channel->stderr_buffer)>0)) + channel->delayed_close=1; + else + channel->open=0; + if(!channel->remote_eof) + ssh_say(2,"Remote host not polite enough to send an eof before close\n"); + channel->remote_eof=1; + /* the remote eof doesn't break things if there was still data into read + * buffer because the eof is ignored until the buffer is empty. */ +} + +static void channel_rcv_request(SSH_SESSION *session){ + STRING *request_s; + char *request; + u32 status; + CHANNEL *channel=channel_from_msg(session); + if(!channel){ + ssh_say(1,"%s\n",ssh_get_error(session)); + return; + } + request_s=buffer_get_ssh_string(session->in_buffer); + if(!request_s){ + ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n"); + return; + } + buffer_get_u8(session->in_buffer,(u8 *)&status); + request=string_to_char(request_s); + if(!strcmp(request,"exit-status")){ + buffer_get_u32(session->in_buffer,&status); + status=ntohl(status); +/* XXX do something with status, we might need it */ + free(request_s); + free(request); + return ; + } + if(!strcmp(request,"exit-signal")){ + STRING *signal_s; + char *signal; + char *core="(core dumped)"; + u8 i; + signal_s=buffer_get_ssh_string(session->in_buffer); + if(!signal_s){ + ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n"); + free(request_s); + free(request); + return; + } + signal=string_to_char(signal_s); + buffer_get_u8(session->in_buffer,&i); + if(!i) + core=""; + ssh_say(0,"Remote connection closed by signal SIG%s %s\n",signal,core); + free(signal_s); + free(signal); + free(request_s); + free(request); + return; + } + ssh_say(0,"Unknown request %s\n",request); + free(request_s); + free(request); +} + +/* channel_handle is called by wait_packet, ie, when there is channel informations to handle . */ +void channel_handle(SSH_SESSION *session, int type){ + ssh_say(3,"Channel_handle(%d)\n",type); + switch(type){ + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + channel_rcv_change_window(session); + break; + case SSH2_MSG_CHANNEL_DATA: + channel_rcv_data(session,0); + break; + case SSH2_MSG_CHANNEL_EXTENDED_DATA: + channel_rcv_data(session,1); + break; + case SSH2_MSG_CHANNEL_EOF: + channel_rcv_eof(session); + break; + case SSH2_MSG_CHANNEL_CLOSE: + channel_rcv_close(session); + break; + case SSH2_MSG_CHANNEL_REQUEST: + channel_rcv_request(session); + break; + default: + ssh_say(0,"Unexpected message %d\n",type); + } +} + +/* when data has been received from the ssh server, it can be applied to the known + user function, with help of the callback, or inserted here */ +/* XXX is the window changed ? */ +void channel_default_bufferize(CHANNEL *channel, void *data, int len, int is_stderr){ + ssh_say(3,"placing %d bytes into channel buffer (stderr=%d)\n",len,is_stderr); + if(!is_stderr){ + /* stdout */ + if(!channel->stdout_buffer) + channel->stdout_buffer=buffer_new(); + buffer_add_data(channel->stdout_buffer,data,len); + } else { + /* stderr */ + if(!channel->stderr_buffer) + channel->stderr_buffer=buffer_new(); + buffer_add_data(channel->stderr_buffer,data,len); + } +} + +int channel_open_session(CHANNEL *channel){ +#ifdef HAVE_SSH1 + if(channel->session->version==2) +#endif + return channel_open(channel,"session",64000,32000,NULL); +#ifdef HAVE_SSH1 + else + return channel_open_session1(channel); +#endif +} + +/* tcpip forwarding */ + +int channel_open_forward(CHANNEL *channel,char *remotehost, int remoteport, char *sourcehost, int localport){ + BUFFER *payload=buffer_new(); + STRING *str=string_from_char(remotehost); + int ret; + buffer_add_ssh_string(payload,str); + free(str); + str=string_from_char(sourcehost); + buffer_add_u32(payload,htonl(remoteport)); + buffer_add_ssh_string(payload,str); + free(str); + buffer_add_u32(payload,htonl(localport)); + ret=channel_open(channel,"direct-tcpip",64000,32000,payload); + buffer_free(payload); + return ret; +} + + +void channel_free(CHANNEL *channel){ + SSH_SESSION *session=channel->session; + if(session->alive && channel->open) + channel_close(channel); + /* handle the "my channel is first on session list" case */ + if(session->channels==channel) + session->channels=channel->next; + /* handle the "my channel is the only on session list" case */ + if(channel->next == channel){ + session->channels=NULL; + } else { + channel->prev->next=channel->next; + channel->next->prev=channel->prev; + } + if(channel->stdout_buffer) + buffer_free(channel->stdout_buffer); + if(channel->stderr_buffer) + buffer_free(channel->stderr_buffer); + /* debug trick to catch use after frees */ + memset(channel,'X',sizeof(CHANNEL)); + free(channel); +} + +int channel_send_eof(CHANNEL *channel){ + SSH_SESSION *session=channel->session; + int ret; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_EOF); + buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)); + ret=packet_send(session); + ssh_say(1,"Sent a EOF on client channel (%d:%d)\n",channel->local_channel, + channel->remote_channel); + channel->local_eof=1; + return ret; +} + +int channel_close(CHANNEL *channel){ + SSH_SESSION *session=channel->session; + int ret=0; + if(!channel->local_eof) + ret=channel_send_eof(channel); + if(ret) + return ret; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_CLOSE); + buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)); + ret=packet_send(session); + ssh_say(1,"Sent a close on client channel (%d:%d)\n",channel->local_channel, + channel->remote_channel); + if(!ret) + channel->open =0; + return ret; +} + +/* Blocking write */ +/* The exact len is written */ +int channel_write(CHANNEL *channel ,void *data,int len){ + SSH_SESSION *session=channel->session; + int effectivelen; + int origlen=len; + if(channel->local_eof){ + ssh_set_error(session,SSH_REQUEST_DENIED,"Can't write to channel %d:%d" + " after EOF was sent",channel->local_channel,channel->remote_channel); + return -1; + } + if(!channel->open || channel->delayed_close){ + ssh_set_error(session,SSH_REQUEST_DENIED,"Remote channel is closed"); + return -1; + } +#ifdef HAVE_SSH1 + if(channel->version==1) + return channel_write1(channel,data,len); +#endif + while(len >0){ + if(channel->remote_windowremote_window,len); + ssh_say(2,"Waiting for a growing window message...\n"); + // wonder what happens when the channel window is zero + while(channel->remote_window==0){ + // parse every incoming packet + packet_wait(channel->session,0,0); + } + effectivelen=len>channel->remote_window?channel->remote_window:len; + } else + effectivelen=len; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_DATA); + buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)); + buffer_add_u32(session->out_buffer,htonl(effectivelen)); + buffer_add_data(session->out_buffer,data,effectivelen); + packet_send(session); + ssh_say(2,"channel_write wrote %d bytes\n",effectivelen); + channel->remote_window-=effectivelen; + len -= effectivelen; + data+=effectivelen; + } + return origlen; +} + +int channel_is_open(CHANNEL *channel){ + return (channel->open!=0); +} + +int channel_is_eof(CHANNEL *channel){ + if((channel->stdout_buffer && buffer_get_rest_len(channel->stdout_buffer) + >0) || (channel->stderr_buffer && buffer_get_rest_len( + channel->stderr_buffer)>0)) + return 0; + return (channel->remote_eof!=0); +} + +void channel_set_blocking(CHANNEL *channel, int blocking){ + channel->blocking=blocking; +} + +static int channel_request(CHANNEL *channel,char *request, BUFFER *buffer,int reply){ + STRING *request_s=string_from_char(request); + SSH_SESSION *session=channel->session; + int err; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_REQUEST); + buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)); + buffer_add_ssh_string(session->out_buffer,request_s); + buffer_add_u8(session->out_buffer,reply?1:0); + if(buffer) + buffer_add_data(session->out_buffer,buffer_get(buffer),buffer_get_len(buffer)); + packet_send(session); + ssh_say(3,"Sent a SSH_MSG_CHANNEL_REQUEST %s\n",request); + free(request_s); + if(!reply) + return 0; + err=packet_wait(session,SSH2_MSG_CHANNEL_SUCCESS,1); + if(err) + if(session->in_packet.type==SSH2_MSG_CHANNEL_FAILURE){ + ssh_say(2,"%s channel request failed\n",request); + ssh_set_error(session,SSH_REQUEST_DENIED,"Channel request %s failed",request); + } + else + ssh_say(3,"Received an unexpected %d message\n",session->in_packet.type); + else + ssh_say(3,"Received a SUCCESS\n"); + return err; +} + +int channel_request_pty_size(CHANNEL *channel, char *terminal, int col, int row){ + STRING *term; + BUFFER *buffer; + int err; +#ifdef HAVE_SSH1 + if(channel->version==1) + return channel_request_pty_size1(channel,terminal, col, row); +#endif + term=string_from_char(terminal); + buffer=buffer_new(); + buffer_add_ssh_string(buffer,term); + buffer_add_u32(buffer,htonl(col)); + buffer_add_u32(buffer,htonl(row)); + buffer_add_u32(buffer,0); + buffer_add_u32(buffer,0); +/* a 0byte string */ + buffer_add_u32(buffer,htonl(1)); + buffer_add_u8(buffer,0); + free(term); + err=channel_request(channel,"pty-req",buffer,1); + buffer_free(buffer); + return err; +} + +int channel_request_pty(CHANNEL *channel){ + return channel_request_pty_size(channel,"xterm",80,24); +} + +int channel_change_pty_size(CHANNEL *channel,int cols,int rows){ + BUFFER *buffer; + int err; +#ifdef HAVE_SSH1 + if(channel->version==1) + return channel_change_pty_size1(channel,cols,rows); +#endif + buffer=buffer_new(); + //buffer_add_u8(buffer,0); + buffer_add_u32(buffer,htonl(cols)); + buffer_add_u32(buffer,htonl(rows)); + buffer_add_u32(buffer,0); + buffer_add_u32(buffer,0); + err=channel_request(channel,"window-change",buffer,0); + buffer_free(buffer); + return err; +} + +int channel_request_shell(CHANNEL *channel){ +#ifdef HAVE_SSH1 + if(channel->version==1) + return channel_request_shell1(channel); +#endif + return channel_request(channel,"shell",NULL,1); +} + +int channel_request_subsystem(CHANNEL *channel, char *system){ + BUFFER* buffer=buffer_new(); + int ret; + STRING *subsystem=string_from_char(system); + buffer_add_ssh_string(buffer,subsystem); + free(subsystem); + ret=channel_request(channel,"subsystem",buffer,1); + buffer_free(buffer); + return ret; +} + +int channel_request_sftp( CHANNEL *channel){ + return channel_request_subsystem(channel, "sftp"); +} + + +int channel_request_env(CHANNEL *channel,char *name, char *value){ + BUFFER *buffer=buffer_new(); + int ret; + STRING *string=string_from_char(name); + buffer_add_ssh_string(buffer,string); + free(string); + string=string_from_char(value); + buffer_add_ssh_string(buffer,string); + free(string); + ret=channel_request(channel,"env",buffer,1); + buffer_free(buffer); + return ret; +} + +int channel_request_exec(CHANNEL *channel, char *cmd){ + BUFFER *buffer; + int ret; +#ifdef HAVE_SSH1 + if(channel->version==1) + return channel_request_exec1(channel, cmd); +#endif + buffer=buffer_new(); + STRING *command=string_from_char(cmd); + buffer_add_ssh_string(buffer,command); + free(command); + ret=channel_request(channel,"exec",buffer,1); + buffer_free(buffer); + return ret; +} + +/* TODO : fix the delayed close thing */ +/* TODO : fix the blocking behaviours */ +/* reads into a channel and put result into buffer */ +/* returns number of bytes read, 0 if eof or such and -1 in case of error */ +/* if bytes != 0, the exact number of bytes are going to be read */ + +int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr){ + BUFFER *stdbuf=NULL; + int len; + buffer_reinit(buffer); + /* maybe i should always set a buffer to avoid races between channel_default_bufferize and channel_read */ + if(is_stderr) + stdbuf=channel->stderr_buffer; + else + stdbuf=channel->stdout_buffer; + + /* block reading if asked bytes=0 */ + while((buffer_get_rest_len(stdbuf)==0) || (buffer_get_rest_len(stdbuf) < bytes)){ + if(channel->remote_eof && buffer_get_rest_len(stdbuf)==0) + return 0; + if(channel->remote_eof) + break; /* return the resting bytes in buffer */ + if(packet_read(channel->session)||packet_translate(channel->session)) + return -1; + packet_parse(channel->session); + } + + if(bytes==0){ + /* write the ful buffer informations */ + buffer_add_data(buffer,buffer_get_rest(stdbuf),buffer_get_rest_len(stdbuf)); + buffer_reinit(stdbuf); + } else { + len=buffer_get_rest_len(stdbuf); + len= (len>bytes?bytes:len); /* read bytes bytes if len is greater, everything otherwise */ + buffer_add_data(buffer,buffer_get_rest(stdbuf),len); + buffer_pass_bytes(stdbuf,len); + } + return buffer_get_len(buffer); +} + +/* returns the number of bytes available, 0 if nothing is currently available, -1 if error */ +int channel_poll(CHANNEL *channel, int is_stderr){ + BUFFER *buffer; + if(is_stderr) + buffer=channel->stderr_buffer; + else + buffer=channel->stdout_buffer; + + while(buffer_get_rest_len(buffer)==0 && !channel->remote_eof){ + if(ssh_fd_poll(channel->session)){ + if(packet_read(channel->session)||packet_translate(channel->session)) + return -1; + packet_parse(channel->session); + } else + return 0; /* nothing is available has said fd_poll */ + } + return buffer_get_len(buffer); +} + +/* nonblocking read on the specified channel. it will return <=len bytes of data read + atomicly. */ +int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr){ + int to_read=channel_poll(channel,is_stderr); + int lu; + BUFFER *buffer=buffer_new(); + if(to_read<=0){ + buffer_free(buffer); + return to_read; /* may be an error code */ + } + if(to_read>len) + to_read=len; + lu=channel_read(channel,buffer,to_read,is_stderr); + memcpy(dest,buffer_get(buffer),lu>=0?lu:0); + buffer_free(buffer); + return lu; +} + +SSH_SESSION *channel_get_session(CHANNEL *channel){ + return channel->session; +} + diff --git a/libssh/client.c b/libssh/client.c new file mode 100644 index 00000000..7f8da567 --- /dev/null +++ b/libssh/client.c @@ -0,0 +1,287 @@ +/* client.c file */ +/* +Copyright 2003-2005 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include "libssh/priv.h" +#include "libssh/ssh2.h" + +#define set_status(opt,status) do {\ + if (opt->connect_status_function) \ + opt->connect_status_function(opt->connect_status_arg, status); \ + } while (0) +/* simply gets a banner from a socket */ + +char *ssh_get_banner(SSH_SESSION *session){ + char buffer[128]; + int i = 0; + while (i < 127) { + if(read(session->fd, &buffer[i], 1)<=0){ + ssh_set_error(session,SSH_FATAL,"Remote host closed connection"); + return NULL; + } + if (buffer[i] == '\r') + buffer[i] = 0; + if (buffer[i] == '\n') { + buffer[i] = 0; + return strdup(buffer); + } + i++; + } + ssh_set_error(NULL,SSH_FATAL,"Too large banner"); + return NULL; +} + +int ssh_analyze_banner(SSH_SESSION *session, int *ssh1, int *ssh2){ + char *banner=session->serverbanner; + if(strncmp(banner,"SSH-",4)!=0){ + ssh_set_error(NULL,SSH_FATAL,"Protocol mismatch: %s",banner); + return -1; + } + /* a typical banner is : + * SSH-1.5-blah + * SSH-1.99-blah + * SSH-2.0-blah + */ + switch(banner[4]){ + case '1': + *ssh1=1; + if(banner[6]=='9') + *ssh2=1; + else + *ssh2=0; + break; + case '2': + *ssh1=0; + *ssh2=1; + break; + default: + ssh_set_error(NULL,SSH_FATAL,"Protocol mismatch: %s",banner); + return -1; + } + return 0; +} + +/* ssh_send_banner sends a SSH banner to the server */ +/* TODO select a banner compatible with server version */ +/* switch SSH1/1.5/2 */ +/* and quit when the server is SSH1 only */ + +void ssh_send_banner(SSH_SESSION *session){ + char *banner; + char buffer[128]; + banner=session->version==1?CLIENTBANNER1:CLIENTBANNER2; + if(session->options->banner) + banner=session->options->banner; + session->clientbanner=strdup(banner); + snprintf(buffer,128,"%s\r\n",session->clientbanner); + write(session->fd,buffer,strlen(buffer)); +} + + +int dh_handshake(SSH_SESSION *session){ + STRING *e,*f,*pubkey,*signature; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT); + dh_generate_x(session); + dh_generate_e(session); + e=dh_get_e(session); + buffer_add_ssh_string(session->out_buffer,e); + packet_send(session); + free(e); + if(packet_wait(session,SSH2_MSG_KEXDH_REPLY,1)) + return -1; + pubkey=buffer_get_ssh_string(session->in_buffer); + if(!pubkey){ + ssh_set_error(NULL,SSH_FATAL,"No public key in packet"); + return -1; + } + dh_import_pubkey(session,pubkey); + f=buffer_get_ssh_string(session->in_buffer); + if(!f){ + ssh_set_error(NULL,SSH_FATAL,"No F number in packet"); + return -1; + } + dh_import_f(session,f); + free(f); + if(!(signature=buffer_get_ssh_string(session->in_buffer))){ + ssh_set_error(NULL,SSH_FATAL,"No signature in packet"); + return -1; + } + + dh_build_k(session); + packet_wait(session,SSH2_MSG_NEWKEYS,1); + ssh_say(2,"Got SSH_MSG_NEWKEYS\n"); + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); + packet_send(session); + ssh_say(2,"SSH_MSG_NEWKEYS sent\n"); + make_sessionid(session); + /* set the cryptographic functions for the next crypto (it is needed for generate_session_keys for key lenghts) */ + if(crypt_set_algorithms(session)) + return -1; + generate_session_keys(session); + /* verify the host's signature. XXX do it sooner */ + if(signature_verify(session,signature)){ + free(signature); + return -1; + } + free(signature); /* forget it for now ... */ + /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ + if(session->current_crypto) + crypto_free(session->current_crypto); + /* XXX later, include a function to change keys */ + session->current_crypto=session->next_crypto; + session->next_crypto=crypto_new(); + return 0; +} + +int ssh_service_request(SSH_SESSION *session,char *service){ + STRING *service_s; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST); + service_s=string_from_char(service); + buffer_add_ssh_string(session->out_buffer,service_s); + free(service_s); + packet_send(session); + ssh_say(3,"Sent SSH_MSG_SERVICE_REQUEST (service %s)\n",service); + if(packet_wait(session,SSH2_MSG_SERVICE_ACCEPT,1)){ + ssh_set_error(session,SSH_FATAL,"did not receive SERVICE_ACCEPT"); + return -1; + } + ssh_say(3,"Received SSH_MSG_SERVICE_ACCEPT (service %s)\n",service); + return 0; +} + +int ssh_connect(SSH_SESSION *session){ + int fd; + int ssh1, ssh2; + SSH_OPTIONS *options=session->options; + if(!session->options){ + ssh_set_error(session,SSH_FATAL,"Must set options before connect"); + return -1; + } + ssh_crypto_init(); + if(options->fd==-1 && !options->host){ + ssh_set_error(session,SSH_FATAL,"Hostname required"); + return -1; + } + if(options->fd != -1) + fd=options->fd; + else + fd=ssh_connect_host(session,options->host,options->bindaddr,options->port, + options->timeout,options->timeout_usec); + if(fd<0) + return -1; + set_status(options,0.2); + session->fd=fd; + session->alive=1; + if(!(session->serverbanner=ssh_get_banner(session))){ + close(fd); + return -1; + } + set_status(options,0.4); + ssh_say(2,"banner : %s\n",session->serverbanner); + /* here we analyse the different protocols the server allows */ + if(ssh_analyze_banner(session,&ssh1,&ssh2)){ + ssh_disconnect(session); + return -1; + } + /* here we decide which version of the protocol to use */ + if(ssh2 && options->ssh2allowed) + session->version=2; + else { + if(ssh1 && options->ssh1allowed) + session->version=1; + else { + ssh_set_error(session,SSH_FATAL, + "no version of SSH protocol usable (banner: %s)", + session->serverbanner); + ssh_disconnect(session); + return -1; + } + } + ssh_send_banner(session); + set_status(options,0.5); + switch(session->version){ + case 2: + if(ssh_get_kex(session,0)){ + ssh_disconnect(session); + return -1; + } + set_status(options,0.6); + list_kex(&session->server_kex); + if(set_kex(session)){ + ssh_disconnect(session); + return -1; + } + send_kex(session,0); + set_status(options,0.8); + if(dh_handshake(session)){ + ssh_disconnect(session); + return -1; + } + set_status(options,1.0); + session->connected=1; + break; + case 1: + if(ssh_get_kex1(session)){ + ssh_disconnect(session); + return -1; + } + set_status(options,0.6); + session->connected=1; + break; + } + return 0; +} + +char *ssh_get_issue_banner(SSH_SESSION *session){ + if(!session->banner) + return NULL; + return string_to_char(session->banner); +} + +void ssh_disconnect(SSH_SESSION *session){ + STRING *str; + if(session->fd!= -1) { + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_DISCONNECT); + buffer_add_u32(session->out_buffer,htonl(SSH2_DISCONNECT_BY_APPLICATION)); + str=string_from_char("Bye Bye"); + buffer_add_ssh_string(session->out_buffer,str); + free(str); + packet_send(session); + close(session->fd); + session->fd=-1; + } + session->alive=0; + ssh_cleanup(session); +} + +const char *ssh_copyright(){ + return LIBSSH_VERSION " (c) 2003-2005 Aris Adamantiadis (aris@0xbadc0de.be)" + " Distributed under the LGPL, please refer to COPYING file for informations" + " about your rights" ; +} diff --git a/libssh/connect.c b/libssh/connect.c new file mode 100644 index 00000000..4e1782d4 --- /dev/null +++ b/libssh/connect.c @@ -0,0 +1,286 @@ +/* connect.c */ +/* it handles connections to ssh servers */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libssh/priv.h" +#ifdef HAVE_SYS_POLL_H +#include +#endif + +#ifndef HAVE_GETHOSTBYNAME +#ifndef HAVE_GETHOSTBYADDR +#error "your system doesn't have gethostbyname nor gethostbyaddr" +#endif +#endif +static void sock_set_nonblocking(int sock) { + fcntl(sock,F_SETFL,O_NONBLOCK); +} +static void sock_set_blocking(int sock){ + fcntl(sock,F_SETFL,0); +} + +/* connect_host connects to an IPv4 (or IPv6) host */ +/* specified by its IP address or hostname. */ +/* output is the file descriptor, <0 if failed. */ + +int ssh_connect_host(SSH_SESSION *session, const char *host, const char + *bind_addr, int port,long timeout, long usec){ + struct sockaddr_in sa; + struct sockaddr_in bindsa; + struct hostent *hp=NULL; + static int count=0; /* for reentrencity */ + int s; + while(++count>1) + --count; +#ifdef HAVE_GETHOSTBYADDR + hp=gethostbyaddr(host,4,AF_INET); +#endif +#ifdef HAVE_GETHOSTBYNAME + if(!hp) + hp=gethostbyname(host); +#endif + if(!hp){ + --count; + ssh_set_error(session,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,hstrerror(h_errno)); + return -1; + } + memset(&sa,0,sizeof(sa)); + memcpy(&sa.sin_addr,hp->h_addr,hp->h_length); + sa.sin_family=hp->h_addrtype; + sa.sin_port=htons((unsigned short)port); + --count; + + if(bind_addr){ + ssh_say(2,"resolving %s\n",bind_addr); + hp=NULL; + while(++count>1) + --count; +#ifdef HAVE_GETHOSTBYADDR + hp=gethostbyaddr(bind_addr,4,AF_INET); +#endif +#ifdef HAVE_GETHOSTBYNAME + if(!hp) + hp=gethostbyname(bind_addr); +#endif + if(!hp){ + --count; + ssh_set_error(session,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,hstrerror(h_errno)); + return -1; + } + } + memset(&bindsa,0,sizeof(bindsa)); + /* create socket */ + s=socket(sa.sin_family,SOCK_STREAM,0); + if(s<0){ + if(bind_addr) + --count; + ssh_set_error(session,SSH_FATAL,"socket : %s",strerror(errno)); + return s; + } + + if(bind_addr){ + memcpy(&bindsa.sin_addr,hp->h_addr,hp->h_length); + bindsa.sin_family=hp->h_addrtype; + --count; + if(bind(s,(struct sockaddr *)&bindsa,sizeof(bindsa))<0){ + ssh_set_error(session,SSH_FATAL,"Binding local address : %s",strerror(errno)); + close(s); + return -1; + } + } + if(timeout){ + struct timeval to; + fd_set set; + int ret=0; + int len=sizeof(ret); + to.tv_sec=timeout; + to.tv_usec=usec; + sock_set_nonblocking(s); + connect(s,(struct sockaddr* )&sa,sizeof(sa)); + FD_ZERO(&set); + FD_SET(s,&set); + ret=select(s+1,NULL,&set,NULL,&to); + if(ret==0){ + /* timeout */ + ssh_set_error(session,SSH_FATAL,"Timeout while connecting to %s:%d",host,port); + close(s); + return -1; + } + if(ret<0){ + ssh_set_error(session,SSH_FATAL,"Select error : %s",strerror(errno)); + close(s); + return -1; + } + /* get connect(2) return code. zero means no error */ + getsockopt(s,SOL_SOCKET,SO_ERROR,&ret,&len); + if (ret!=0){ + ssh_set_error(session,SSH_FATAL,"Connecting : %s",strerror(ret)); + close(s); + return -1; + } + /* s is connected ? */ + ssh_say(3,"socket connected with timeout\n"); + sock_set_blocking(s); + return s; + } + if(connect(s,(struct sockaddr *)&sa,sizeof(sa))< 0){ + close(s); + ssh_set_error(session,SSH_FATAL,"connect: %s",strerror(errno)); + return -1; + } + return s; +} + +/* returns 1 if bytes are available on the stream, 0 instead */ +int ssh_fd_poll(SSH_SESSION *session){ +#ifdef HAVE_POLL + struct pollfd fdset; +#else + struct timeval sometime; + fd_set descriptor; +#endif + if(session->data_to_read) + return(session->data_to_read); +#ifdef HAVE_POLL + fdset.fd=session->fd; + fdset.events=POLLHUP|POLLIN|POLLPRI; + fdset.revents=0; + if(poll(&fdset,1,0)==0) + return 0; + if(fdset.revents & (POLLHUP|POLLIN|POLLPRI)) + return (session->data_to_read=1); + return 0; +#elif HAVE_SELECT + + /* Set to return immediately (no blocking) */ + sometime.tv_sec = 0; + sometime.tv_usec = 0; + + /* Set up descriptor */ + FD_ZERO(&descriptor); + FD_SET(session->fd, &descriptor); + + /* Make the call, and listen for errors */ + if (select(session->fd + 1, &descriptor, NULL, NULL, &sometime) < 0) { + ssh_set_error(NULL,SSH_FATAL, "select: %s", strerror(errno)); + return -1; + } + session->data_to_read=FD_ISSET(session->fd,&descriptor); + return session->data_to_read; +#else +#error This system does not have poll() or select(), so ssh_fd_poll() will not work correctly + return 0; +#endif +} + +/* this function is a complete wrapper for the select syscall. it does more than wrapping ... */ +int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout){ + struct timeval zerotime; + fd_set localset,localset2; + int rep; + int i,j; + int set; + + zerotime.tv_sec=0; + zerotime.tv_usec=0; + /* first, poll the maxfd file descriptors from the user with a zero-second timeout. they have the bigger priority */ + if(maxfd>0){ + memcpy(&localset,readfds, sizeof(fd_set)); + rep=select(maxfd,&localset,NULL,NULL,&zerotime); + // catch the eventual errors + if(rep==-1) + return -1; + } + j=0; + // polls every channel. + for(i=0;channels[i];i++){ + if(channel_poll(channels[i],0)>0){ + outchannels[j]=channels[i]; + j++; + } else + if(channel_poll(channels[i],1)>0){ + outchannels[j]=channels[i]; + j++; + } + } + outchannels[j]=NULL; + /* look into the localset for active fd */ + set=0; + for(i=0;(i0) + memcpy(readfds,&localset,sizeof(fd_set)); + return 0; + } + /* at this point, not any channel had any data ready for reading, nor any fd had data for reading */ + memcpy(&localset,readfds,sizeof(fd_set)); + for(i=0;channels[i];i++){ + if(channels[i]->session->alive){ + FD_SET(channels[i]->session->fd,&localset); + if(channels[i]->session->fd>maxfd-1) + maxfd=channels[i]->session->fd+1; + } + } + rep=select(maxfd,&localset,NULL,NULL,timeout); + if(rep==-1 && errno==EINTR){ + return SSH_EINTR; /* interrupted by a signal */ + } + if(rep==-1){ + /* was the error due to a libssh's Channel or from a closed descriptor from the user ? user closed descriptors have been + caught in the first select and not closed since that moment. that case shouldn't occur at all */ + return -1; + } + /* set the data_to_read flag on each session */ + for(i=0;channels[i];i++) + if(FD_ISSET(channels[i]->session->fd,&localset)) + channels[i]->session->data_to_read=1; + + /* now, test each channel */ + j=0; + for(i=0;channels[i];i++){ + if(FD_ISSET(channels[i]->session->fd,&localset)) + if((channel_poll(channels[i],0)>0) || (channel_poll(channels[i],1)>0)){ + outchannels[j]=channels[i]; + j++; + } + } + outchannels[j]=NULL; + FD_ZERO(&localset2); + for(i=0;i0){ + ret=crc_table[(ret ^ *buf) & 0xff] ^ (ret >> 8); + --len; + ++buf; + } + return ret; +} + diff --git a/libssh/crypt.c b/libssh/crypt.c new file mode 100644 index 00000000..5daab609 --- /dev/null +++ b/libssh/crypt.c @@ -0,0 +1,105 @@ +/* crypt.c */ +/* it just contains the shit necessary to make blowfish-cbc work ... */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include + +#include +#include +#include + +#include +#include "libssh/priv.h" +#include "libssh/crypto.h" + +u32 packet_decrypt_len(SSH_SESSION *session, char *crypted){ + u32 *decrypted; + if(session->current_crypto) + packet_decrypt(session,crypted,session->current_crypto->in_cipher->blocksize); + decrypted=(u32 *)crypted; + ssh_say(3,"size decrypted : %lx\n",ntohl(*decrypted)); + return ntohl(*decrypted); +} + +int packet_decrypt(SSH_SESSION *session, void *data,u32 len){ + struct crypto_struct *crypto=session->current_crypto->in_cipher; + char *out=malloc(len); + ssh_say(3,"Decrypting %d bytes data\n",len); + crypto->set_decrypt_key(crypto,session->current_crypto->decryptkey); + crypto->cbc_decrypt(crypto,data,out,len,session->current_crypto->decryptIV); + memcpy(data,out,len); + memset(out,0,len); + free(out); + return 0; +} + +char * packet_encrypt(SSH_SESSION *session,void *data,u32 len){ + struct crypto_struct *crypto; + HMAC_CTX *ctx; + char *out; + int finallen; + u32 seq=ntohl(session->send_seq); + if(!session->current_crypto) + return NULL; /* nothing to do here */ + crypto= session->current_crypto->out_cipher; + ssh_say(3,"seq num = %d, len = %d\n",session->send_seq,len); + crypto->set_encrypt_key(crypto,session->current_crypto->encryptkey); + out=malloc(len); + if(session->version==2){ + ctx=hmac_init(session->current_crypto->encryptMAC,20,HMAC_SHA1); + hmac_update(ctx,(unsigned char *)&seq,sizeof(u32)); + hmac_update(ctx,data,len); + hmac_final(ctx,session->current_crypto->hmacbuf,&finallen); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("mac :",data,len); + if(finallen!=20) + printf("Final len is %d\n",finallen); + ssh_print_hexa("packet hmac",session->current_crypto->hmacbuf,20); +#endif + } + crypto->cbc_encrypt(crypto,data,out,len,session->current_crypto->encryptIV); + memcpy(data,out,len); + memset(out,0,len); + free(out); + if(session->version==2) + return session->current_crypto->hmacbuf; + else + return NULL; +} + +int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,char *mac){ + HMAC_CTX *ctx; + unsigned char hmacbuf[EVP_MAX_MD_SIZE]; + int len; + u32 seq=htonl(session->recv_seq); + ctx=hmac_init(session->current_crypto->decryptMAC,20,HMAC_SHA1); + hmac_update(ctx,(unsigned char *)&seq,sizeof(u32)); + hmac_update(ctx,buffer_get(buffer),buffer_get_len(buffer)); + hmac_final(ctx,hmacbuf,&len); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("received mac",mac,len); + ssh_print_hexa("Computed mac",hmacbuf,len); + ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(u32)); +#endif + return memcmp(mac,hmacbuf,len); +} diff --git a/libssh/dh.c b/libssh/dh.c new file mode 100644 index 00000000..25bf5ae6 --- /dev/null +++ b/libssh/dh.c @@ -0,0 +1,412 @@ +/* dh.c */ +/* this file contains usefull stuff for Diffie helman algorithm against SSH 2 */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* Let us resume the dh protocol. */ +/* Each side computes a private prime number, x at client side, y at server side. */ +/* g and n are two numbers common to every ssh software. */ +/* client's public key (e) is calculated by doing */ +/* e = g^x mod p */ +/* client sents e to the server . */ +/* the server computes his own public key, f */ +/* f = g^y mod p */ +/* it sents it to the client */ +/* the common key K is calculated by the client by doing */ +/* k = f^x mod p */ +/* the server does the same with the client public key e */ +/* k' = e^y mod p */ +/* if everything went correctly, k and k' are equal */ + +#include +#include +#include +#include +#include +#include "libssh/priv.h" + +#include +#include +#include +#include +#include "libssh/crypto.h" +static unsigned char p_value[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, + 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, + 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, + 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, + 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, + 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +#define P_LEN 128 /* Size in bytes of the p number */ + +static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */ +static bignum g; +static bignum p; + +/* maybe it might be enhanced .... */ +/* XXX Do it. */ +void ssh_get_random(void *where, int len){ + static int rndfd=0; + if(!rndfd){ + rndfd=open("/dev/urandom",O_RDONLY); + if(rndfd<0){ + fprintf(stderr,"Can't open /dev/urandom\n"); + exit(-1); + } + } + read(rndfd,where,len); +} + +/* it inits the values g and p which are used for DH key agreement */ +void ssh_crypto_init(){ + static int init=0; + if(!init){ + g=bignum_new(); + bignum_set_word(g,g_int); + p=bignum_new(); + bignum_bin2bn(p_value,P_LEN,p); + init++; + } +} + +/* prints the bignum on stderr */ +void ssh_print_bignum(char *which,bignum num){ + char *hex; + fprintf(stderr,"%s value: ",which); + hex=bignum_bn2hex(num); + fprintf(stderr,"%s\n",hex); + free(hex); +} + +void ssh_print_hexa(char *descr,unsigned char *what, int len){ + int i; + printf("%s : ",descr); + for(i=0;inext_crypto->x=bignum_new(); + bignum_rand(session->next_crypto->x,128,0,-1); + /* not harder than this */ +#ifdef DEBUG_CRYPTO + ssh_print_bignum("x",session->next_crypto->x); +#endif +} + +void dh_generate_e(SSH_SESSION *session){ + bignum_CTX ctx=bignum_ctx_new(); + session->next_crypto->e=bignum_new(); + bignum_mod_exp(session->next_crypto->e,g,session->next_crypto->x,p,ctx); +#ifdef DEBUG_CRYPTO + ssh_print_bignum("e",session->next_crypto->e); +#endif + bignum_ctx_free(ctx); +} + + +STRING *make_bignum_string(bignum num){ + STRING *ptr; + int pad=0; + int len=bignum_num_bytes(num); + int bits=bignum_num_bits(num); + int finallen; + /* remember if the fist bit is set, it is considered as a negative number. so 0's must be appended */ + if(!(bits%8) && bignum_is_bit_set(num,bits-1)) + pad++; + ssh_say(3,"%d bits, %d bytes, %d padding\n",bits,len,pad); + ptr=malloc(4 + len + pad); + ptr->size=htonl(len+pad); + if(pad) + ptr->string[0]=0; + finallen=bignum_bn2bin(num,ptr->string+pad); + return ptr; +} + +bignum make_string_bn(STRING *string){ + int len=ntohl(string->size); + ssh_say(3,"Importing a %d bits,%d bytes object ...\n",len*8,len); + return bignum_bin2bn(string->string,len,NULL); +} + +STRING *dh_get_e(SSH_SESSION *session){ + return make_bignum_string(session->next_crypto->e); +} + +void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string){ + session->next_crypto->server_pubkey=pubkey_string; +} + +void dh_import_f(SSH_SESSION *session,STRING *f_string){ + session->next_crypto->f=make_string_bn(f_string); +#ifdef DEBUG_CRYPTO + ssh_print_bignum("f",session->next_crypto->f); +#endif +} + +void dh_build_k(SSH_SESSION *session){ + bignum_CTX ctx=bignum_ctx_new(); + session->next_crypto->k=bignum_new(); + bignum_mod_exp(session->next_crypto->k,session->next_crypto->f,session->next_crypto->x,p,ctx); +#ifdef DEBUG_CRYPTO + ssh_print_bignum("shared secret key",session->next_crypto->k); +#endif + bignum_ctx_free(ctx); +} + +static void sha_add(STRING *str,SHACTX *ctx){ + sha1_update(ctx,str,string_len(str)+4); +} + +void make_sessionid(SSH_SESSION *session){ + SHACTX *ctx; + STRING *num,*str; + int len; + ctx=sha1_init(); + + str=string_from_char(session->clientbanner); + sha_add(str,ctx); + free(str); + + str=string_from_char(session->serverbanner); + sha_add(str,ctx); + free(str); + + buffer_add_u32(session->in_hashbuf,0); + buffer_add_u8(session->in_hashbuf,0); + buffer_add_u32(session->out_hashbuf,0); + buffer_add_u8(session->out_hashbuf,0); + + len=ntohl(buffer_get_len(session->out_hashbuf)); + sha1_update(ctx,&len,4); + + sha1_update(ctx,buffer_get(session->out_hashbuf),buffer_get_len(session->out_hashbuf)); + buffer_free(session->out_hashbuf); + session->out_hashbuf=NULL; + + len=ntohl(buffer_get_len(session->in_hashbuf)); + sha1_update(ctx,&len,4); + + sha1_update(ctx,buffer_get(session->in_hashbuf),buffer_get_len(session->in_hashbuf)); + buffer_free(session->in_hashbuf); + session->in_hashbuf=NULL; + sha1_update(ctx,session->next_crypto->server_pubkey,len=(string_len(session->next_crypto->server_pubkey)+4)); + num=make_bignum_string(session->next_crypto->e); + sha1_update(ctx,num,len=(string_len(num)+4)); + free(num); + num=make_bignum_string(session->next_crypto->f); + sha1_update(ctx,num,len=(string_len(num)+4)); + free(num); + num=make_bignum_string(session->next_crypto->k); + sha1_update(ctx,num,len=(string_len(num)+4)); + free(num); + sha1_final(session->next_crypto->session_id,ctx); + +#ifdef DEBUG_CRYPTO + printf("Session hash : "); + ssh_print_hexa("session id",session->next_crypto->session_id,SHA_DIGEST_LENGTH); +#endif +} + +void hashbufout_add_cookie(SSH_SESSION *session){ + session->out_hashbuf=buffer_new(); + buffer_add_u8(session->out_hashbuf,20); + buffer_add_data(session->out_hashbuf,session->client_kex.cookie,16); +} + + +void hashbufin_add_cookie(SSH_SESSION *session,unsigned char *cookie){ + session->in_hashbuf=buffer_new(); + buffer_add_u8(session->in_hashbuf,20); + buffer_add_data(session->in_hashbuf,cookie,16); +} + +static void generate_one_key(STRING *k,char session_id[SHA_DIGEST_LENGTH],char output[SHA_DIGEST_LENGTH],char letter){ + SHACTX *ctx=sha1_init(); + sha1_update(ctx,k,string_len(k)+4); + sha1_update(ctx,session_id,SHA_DIGEST_LENGTH); + sha1_update(ctx,&letter,1); + sha1_update(ctx,session_id,SHA_DIGEST_LENGTH); + sha1_final(output,ctx); +} + +void generate_session_keys(SSH_SESSION *session){ + STRING *k_string; + SHACTX *ctx; + k_string=make_bignum_string(session->next_crypto->k); + + /* IV */ + generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptIV,'A'); + generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptIV,'B'); + + generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptkey,'C'); + + /* some ciphers need more than 20 bytes of input key */ + if(session->next_crypto->out_cipher->keylen > SHA_DIGEST_LENGTH*8){ + ctx=sha1_init(); + sha1_update(ctx,k_string,string_len(k_string)+4); + sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH); + sha1_update(ctx,session->next_crypto->encryptkey,SHA_DIGEST_LENGTH); + sha1_final(session->next_crypto->encryptkey+SHA_DIGEST_LEN,ctx); + } + + generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptkey,'D'); + + if(session->next_crypto->in_cipher->keylen > SHA_DIGEST_LENGTH*8){ + ctx=sha1_init(); + sha1_update(ctx,k_string,string_len(k_string)+4); + sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH); + sha1_update(ctx,session->next_crypto->decryptkey,SHA_DIGEST_LENGTH); + sha1_final(session->next_crypto->decryptkey+SHA_DIGEST_LEN,ctx); + } + + generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptMAC,'E'); + generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptMAC,'F'); + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("client->server IV",session->next_crypto->encryptIV,SHA_DIGEST_LENGTH); + ssh_print_hexa("server->client IV",session->next_crypto->decryptIV,SHA_DIGEST_LENGTH); + ssh_print_hexa("encryption key",session->next_crypto->encryptkey,16); + ssh_print_hexa("decryption key",session->next_crypto->decryptkey,16); + ssh_print_hexa("Encryption MAC",session->next_crypto->encryptMAC,SHA_DIGEST_LENGTH); + ssh_print_hexa("Decryption MAC",session->next_crypto->decryptMAC,20); +#endif + free(k_string); +} + +int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]){ + STRING *pubkey=session->current_crypto->server_pubkey; + MD5CTX *ctx; + int len=string_len(pubkey); + + ctx=md5_init(); + md5_update(ctx,pubkey->string,len); + md5_final(hash,ctx); + return MD5_DIGEST_LEN; +} + +int pubkey_get_hash(SSH_SESSION *session, char hash[MD5_DIGEST_LEN]){ + return ssh_get_pubkey_hash(session,hash); +} + +STRING *ssh_get_pubkey(SSH_SESSION *session){ + return string_copy(session->current_crypto->server_pubkey); +} + +/* XXX i doubt it is still needed, or may need some fix */ +static int match(char *group,char *object){ + char *ptr,*saved; + char *end; + ptr=strdup(group); + saved=ptr; + while(1){ + end=strchr(ptr,','); + if(end) + *end=0; + if(!strcmp(ptr,object)){ + free(saved); + return 0; + } + if(end) + ptr=end+1; + else{ + free(saved); + return -1; + } + } + /* not reached */ + return 1; +} + +static int sig_verify(SSH_SESSION *session, PUBLIC_KEY *pubkey, SIGNATURE *signature, + char *digest){ + int valid=0; + char hash[SHA_DIGEST_LENGTH]; + sha1(digest,SHA_DIGEST_LENGTH,hash); + switch(pubkey->type){ + case TYPE_DSS: + valid=DSA_do_verify(hash,SHA_DIGEST_LENGTH,signature->dsa_sign, + pubkey->dsa_pub); + if(valid==1) + return 0; + if(valid==-1){ + ssh_set_error(session,SSH_FATAL,"DSA error : %s",ERR_error_string(ERR_get_error(),NULL)); + return -1; + } + ssh_set_error(session,SSH_FATAL,"Invalid DSA signature"); + return -1; + case TYPE_RSA: + case TYPE_RSA1: + valid=RSA_verify(NID_sha1,hash,SHA_DIGEST_LENGTH, + signature->rsa_sign->string,string_len(signature->rsa_sign),pubkey->rsa_pub); + if(valid==1) + return 0; + if(valid==-1){ + ssh_set_error(session,SSH_FATAL,"RSA error : %s",ERR_error_string(ERR_get_error(),NULL)); + return -1; + } + ssh_set_error(session,SSH_FATAL,"Invalid RSA signature"); + return -1; + default: + ssh_set_error(session,SSH_FATAL,"Unknown public key type"); + return -1; + } +return -1; +} + + +int signature_verify(SSH_SESSION *session,STRING *signature){ + PUBLIC_KEY *pubkey; + SIGNATURE *sign; + int err; + if(session->options->dont_verify_hostkey){ + ssh_say(1,"Host key wasn't verified\n"); + return 0; + } + pubkey=publickey_from_string(session->next_crypto->server_pubkey); + if(!pubkey) + return -1; + if(session->options->wanted_methods[SSH_HOSTKEYS]){ + if(match(session->options->wanted_methods[SSH_HOSTKEYS],pubkey->type_c)){ + ssh_set_error(session,SSH_FATAL,"Public key from server (%s) doesn't match user preference (%s)", + pubkey->type,session->options->wanted_methods[SSH_HOSTKEYS]); + publickey_free(pubkey); + return -1; + } + } + sign=signature_from_string(signature,pubkey,pubkey->type); + if(!sign){ + ssh_set_error(session,SSH_FATAL,"Invalid signature blob"); + publickey_free(pubkey); + return -1; + } + ssh_say(1,"Going to verify a %s type signature\n",pubkey->type_c); + err=sig_verify(session,pubkey,sign,session->next_crypto->session_id); + signature_free(sign); + session->next_crypto->server_pubkey_type=pubkey->type_c; + publickey_free(pubkey); + return err; +} diff --git a/libssh/error.c b/libssh/error.c new file mode 100644 index 00000000..f3db7948 --- /dev/null +++ b/libssh/error.c @@ -0,0 +1,56 @@ +/* error.c */ +/* it does contain error processing functions */ +/* +Copyright 2003,04 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include "libssh/priv.h" + +static int verbosity; + +/* ssh_set_error registers an error with a description. the error code is the class of error, and description is obvious.*/ +void ssh_set_error(SSH_SESSION *session,int code,char *descr,...){ + va_list va; + va_start(va,descr); + vsnprintf(session->error_buffer,ERROR_BUFFERLEN,descr,va); + va_end(va); + session->error_code=code; +} + +char *ssh_get_error(SSH_SESSION *session){ + return session->error_buffer; +} + +int ssh_get_error_code(SSH_SESSION *session){ + return session->error_code; +} + +void ssh_say(int priority, char *format,...){ + va_list va; + va_start(va,format); + if(priority <= verbosity) + vfprintf(stderr,format,va); + va_end(va); +} + +void ssh_set_verbosity(int num){ + verbosity=num; +} diff --git a/libssh/gzip.c b/libssh/gzip.c new file mode 100644 index 00000000..0b04f905 --- /dev/null +++ b/libssh/gzip.c @@ -0,0 +1,140 @@ +/* gzip.c */ +/* include hooks for compression of packets */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ +#include "libssh/priv.h" +#ifdef HAVE_LIBZ +#undef NO_GZIP +#else +#define NO_GZIP +#endif + +#ifndef NO_GZIP +#include +#include +#define BLOCKSIZE 4092 + +static z_stream *initcompress(SSH_SESSION *session,int level){ + z_stream *stream=malloc(sizeof(z_stream)); + int status; + memset(stream,0,sizeof(z_stream)); + status=deflateInit(stream,level); + if (status!=0) + ssh_set_error(session,SSH_FATAL,"status %d inititalising zlib deflate",status); + return stream; +} + +BUFFER *gzip_compress(SSH_SESSION *session,BUFFER *source,int level){ + BUFFER *dest; + static unsigned char out_buf[BLOCKSIZE]; + void *in_ptr=buffer_get(source); + unsigned long in_size=buffer_get_len(source); + unsigned long len; + int status; + z_stream *zout=session->current_crypto->compress_out_ctx; + if(!zout) + zout=session->current_crypto->compress_out_ctx=initcompress(session,level); + dest=buffer_new(); + zout->next_out=out_buf; + zout->next_in=in_ptr; + zout->avail_in=in_size; + do { + zout->avail_out=BLOCKSIZE; + status=deflate(zout,Z_PARTIAL_FLUSH); + if(status !=0){ + ssh_set_error(session,SSH_FATAL,"status %d deflating zlib packet",status); + return NULL; + } + len=BLOCKSIZE-zout->avail_out; + buffer_add_data(dest,out_buf,len); + zout->next_out=out_buf; + } while (zout->avail_out == 0); + + return dest; +} + +int compress_buffer(SSH_SESSION *session,BUFFER *buf){ + BUFFER *dest=gzip_compress(session,buf,9); + if(!dest) + return -1; + buffer_reinit(buf); + buffer_add_data(buf,buffer_get(dest),buffer_get_len(dest)); + buffer_free(dest); + return 0; +} + +/* decompression */ + +static z_stream *initdecompress(SSH_SESSION *session){ + z_stream *stream=malloc(sizeof(z_stream)); + int status; + memset(stream,0,sizeof(z_stream)); + status=inflateInit(stream); + if (status!=0){ + ssh_set_error(session,SSH_FATAL,"Status = %d initiating inflate context !",status); + free(stream); + stream=NULL; + } + return stream; +} + +BUFFER *gzip_decompress(SSH_SESSION *session,BUFFER *source){ + BUFFER *dest; + static unsigned char out_buf[BLOCKSIZE]; + void *in_ptr=buffer_get_rest(source); + unsigned long in_size=buffer_get_rest_len(source); + unsigned long len; + int status; + z_stream *zin=session->current_crypto->compress_in_ctx; + if(!zin) + zin=session->current_crypto->compress_in_ctx=initdecompress(session); + dest=buffer_new(); + zin->next_out=out_buf; + zin->next_in=in_ptr; + zin->avail_in=in_size; + do { + zin->avail_out=BLOCKSIZE; + status=inflate(zin,Z_PARTIAL_FLUSH); + if(status !=Z_OK){ + ssh_set_error(session,SSH_FATAL,"status %d inflating zlib packet",status); + buffer_free(dest); + return NULL; + } + len=BLOCKSIZE-zin->avail_out; + buffer_add_data(dest,out_buf,len); + zin->next_out=out_buf; + } while (zin->avail_out == 0); + + return dest; +} + +int decompress_buffer(SSH_SESSION *session,BUFFER *buf){ + BUFFER *dest=gzip_decompress(session,buf); + buffer_reinit(buf); + if(!dest){ + return -1; /* failed */ + } + buffer_reinit(buf); + buffer_add_data(buf,buffer_get(dest),buffer_get_len(dest)); + buffer_free(dest); + return 0; +} + +#endif /* NO_GZIP */ diff --git a/libssh/kex.c b/libssh/kex.c new file mode 100644 index 00000000..4a8c30be --- /dev/null +++ b/libssh/kex.c @@ -0,0 +1,439 @@ +/* kex.c is used well, in key exchange :-) */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include +#include "libssh/priv.h" +#include "libssh/ssh2.h" +#include "libssh/ssh1.h" + +#ifdef HAVE_OPENSSL_BLOWFISH_H +#define BLOWFISH "blowfish-cbc," +#else +#define BLOWFISH "" +#endif +#ifdef HAVE_OPENSSL_AES_H +#define AES "aes256-cbc,aes192-cbc,aes128-cbc," +#else +#define AES "" +#endif + +#define DES "3des-cbc," +#ifdef HAVE_LIBZ +#define ZLIB "none,zlib" +#else +#define ZLIB "none" +#endif +char *default_methods[]={ + "diffie-hellman-group1-sha1","ssh-dss,ssh-rsa",AES BLOWFISH DES,AES BLOWFISH + DES, "hmac-sha1","hmac-sha1","none","none","","",NULL }; +char *supported_methods[]={ + "diffie-hellman-group1-sha1","ssh-dss,ssh-rsa",AES BLOWFISH DES,AES BLOWFISH + DES, "hmac-sha1","hmac-sha1",ZLIB,ZLIB,"","",NULL }; +/* descriptions of the key exchange packet */ +char *ssh_kex_nums[]={ + "kex algos","server host key algo","encryption client->server","encryption server->client", + "mac algo client->server","mac algo server->client","compression algo client->server", + "compression algo server->client","languages client->server","languages server->client",NULL}; + +/* tokenize will return a token of strings delimited by ",". the first element has to be freed */ +static char **tokenize(char *chain){ + char **tokens; + int n=1; + int i=0; + char *ptr=chain=strdup(chain); + while(*ptr){ + if(*ptr==','){ + n++; + *ptr=0; + } + ptr++; + } + /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */ + tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */ + ptr=chain; + for(i=0;iin_buffer,session->server_kex.cookie,16)!=16){ + ssh_set_error(session,SSH_FATAL,"get_kex(): no cookie in packet"); + return -1; + } + hashbufin_add_cookie(session,session->server_kex.cookie); + memset(strings,0,sizeof(char *)*10); + for(i=0;i<10;++i){ + str=buffer_get_ssh_string(session->in_buffer); + if(!str) + break; + if(str){ + buffer_add_ssh_string(session->in_hashbuf,str); + strings[i]=string_to_char(str); + free(str); + } else + strings[i]=NULL; + } + /* copy the server kex info into an array of strings */ + if(server_kex){ + session->client_kex.methods=malloc( 10 * sizeof(char **)); + for(i=0;i<10;++i) + session->client_kex.methods[i]=strings[i]; + } else { // client + session->server_kex.methods=malloc( 10 * sizeof(char **)); + for(i=0;i<10;++i) + session->server_kex.methods[i]=strings[i]; + } + return 0; +} + +void list_kex(KEX *kex){ + int i=0; +#ifdef DEBUG_CRYPTO + ssh_print_hexa("session cookie",kex->cookie,16); +#endif + for(i=0;i<10;i++){ + ssh_say(2,"%s : %s\n",ssh_kex_nums[i],kex->methods[i]); + } +} + +/* set_kex basicaly look at the option structure of the session and set the output kex message */ +/* it must be aware of the server kex message */ +/* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */ + +int set_kex(SSH_SESSION *session){ + KEX *server = &session->server_kex; + KEX *client=&session->client_kex; + SSH_OPTIONS *options=session->options; + int i; + char *wanted; + /* the client might ask for a specific cookie to be sent. useful for server debugging */ + if(options->wanted_cookie) + memcpy(client->cookie,options->wanted_cookie,16); + else + ssh_get_random(client->cookie,16); + client->methods=malloc(10 * sizeof(char **)); + memset(client->methods,0,10*sizeof(char **)); + for (i=0;i<10;i++){ + if(!(wanted=options->wanted_methods[i])) + wanted=default_methods[i]; + client->methods[i]=find_matching(server->methods[i],wanted); + if(!client->methods[i] && i < SSH_LANG_C_S){ + ssh_set_error(session,SSH_FATAL,"kex error : did not find one of algos %s in list %s for %s", + wanted,server->methods[i],ssh_kex_nums[i]); + return -1; + } else { + if(i>=SSH_LANG_C_S && !client->methods[i]) + client->methods[i]=strdup(""); // we can safely do that for languages + } + } + return 0; +} + +/* this function only sends the predefined set of kex methods */ +void send_kex(SSH_SESSION *session, int server_kex){ + STRING *str; + int i=0; + KEX *kex=(server_kex ? &session->server_kex : &session->client_kex); + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_KEXINIT); + buffer_add_data(session->out_buffer,kex->cookie,16); + hashbufout_add_cookie(session); + list_kex(kex); + for(i=0;i<10;i++){ + str=string_from_char(kex->methods[i]); + buffer_add_ssh_string(session->out_hashbuf,str); + buffer_add_ssh_string(session->out_buffer,str); + free(str); + } + i=0; + buffer_add_u8(session->out_buffer,0); + buffer_add_u32(session->out_buffer,0); + packet_send(session); +} + +/* returns 1 if at least one of the name algos is in the default algorithms table */ +int verify_existing_algo(int algo, char *name){ + char *ptr; + if(algo>9 || algo <0) + return -1; + ptr=find_matching(supported_methods[algo],name); + if(ptr){ + free(ptr); + return 1; + } + return 0; +} + +/* makes a STRING contating 3 strings : ssh-rsa1,e and n */ +/* this is a public key in openssh's format */ +static STRING *make_rsa1_string(STRING *e, STRING *n){ + BUFFER *buffer=buffer_new(); + STRING *rsa=string_from_char("ssh-rsa1"); + STRING *ret; + buffer_add_ssh_string(buffer,rsa); + free(rsa); + buffer_add_ssh_string(buffer,e); + buffer_add_ssh_string(buffer,n); + ret=string_new(buffer_get_len(buffer)); + string_fill(ret,buffer_get(buffer),buffer_get_len(buffer)); + buffer_free(buffer); + return ret; +} + +static void build_session_id1(SSH_SESSION *session, STRING *servern, + STRING *hostn){ + MD5CTX *md5=md5_init(); + ssh_print_hexa("host modulus",hostn->string,string_len(hostn)); + ssh_print_hexa("server modulus",servern->string,string_len(servern)); + md5_update(md5,hostn->string,string_len(hostn)); + md5_update(md5,servern->string,string_len(servern)); + md5_update(md5,session->server_kex.cookie,8); + md5_final(session->next_crypto->session_id,md5); + ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_LEN); +} + +STRING *encrypt_session_key(SSH_SESSION *session, PUBLIC_KEY *svrkey, + PUBLIC_KEY *hostkey){ + char buffer[32]; + int i; + STRING *data1,*data2; + /* first, generate a session key */ + + ssh_get_random(session->next_crypto->encryptkey,32); + memcpy(buffer,session->next_crypto->encryptkey,32); + memcpy(session->next_crypto->decryptkey, + session->next_crypto->encryptkey,32); + ssh_print_hexa("session key",buffer,32); + /* xor session key with session_id */ + for (i=0;i<16;++i) + buffer[i]^=session->next_crypto->session_id[i]; + data1=string_new(32); + string_fill(data1,buffer,32); + data2=ssh_encrypt_rsa1(session,data1,svrkey); + free(data1); + data1=ssh_encrypt_rsa1(session,data2,hostkey); + return data1; +} + + +/* SSH-1 functions */ +/* 2 SSH_SMSG_PUBLIC_KEY + * + * 8 bytes anti_spoofing_cookie + * 32-bit int server_key_bits + * mp-int server_key_public_exponent + * mp-int server_key_public_modulus + * 32-bit int host_key_bits + * mp-int host_key_public_exponent + * mp-int host_key_public_modulus + * 32-bit int protocol_flags + * 32-bit int supported_ciphers_mask + * 32-bit int supported_authentications_mask + */ + +int ssh_get_kex1(SSH_SESSION *session){ + u32 server_bits, host_bits, protocol_flags, + supported_ciphers_mask, supported_authentications_mask; + STRING *server_exp=NULL; + STRING *server_mod=NULL; + STRING *host_exp=NULL; + STRING *host_mod=NULL; + STRING *serverkey; + STRING *hostkey; + STRING *enc_session; + PUBLIC_KEY *svr,*host; + int ko; + u16 bits; + ssh_say(3,"Waiting for a SSH_SMSG_PUBLIC_KEY\n"); + if(packet_wait(session,SSH_SMSG_PUBLIC_KEY,1)){ + return -1; + } + ssh_say(3,"Got a SSH_SMSG_PUBLIC_KEY\n"); + if(buffer_get_data(session->in_buffer,session->server_kex.cookie,8)!=8){ + ssh_set_error(NULL,SSH_FATAL,"Can't get cookie in buffer"); + return -1; + } + buffer_get_u32(session->in_buffer,&server_bits); + server_exp=buffer_get_mpint(session->in_buffer); + server_mod=buffer_get_mpint(session->in_buffer); + buffer_get_u32(session->in_buffer,&host_bits); + host_exp=buffer_get_mpint(session->in_buffer); + host_mod=buffer_get_mpint(session->in_buffer); + buffer_get_u32(session->in_buffer,&protocol_flags); + buffer_get_u32(session->in_buffer,&supported_ciphers_mask); + ko=buffer_get_u32(session->in_buffer,&supported_authentications_mask); + if((ko!=sizeof(u32)) || !host_mod || !host_exp || !server_mod || !server_exp){ + ssh_say(2,"Invalid SSH_SMSG_PUBLIC_KEY packet\n"); + ssh_set_error(NULL,SSH_FATAL,"Invalid SSH_SMSG_PUBLIC_KEY packet"); + if(host_mod) + free(host_mod); + if(host_exp) + free(host_exp); + if(server_mod) + free(server_mod); + if(server_exp) + free(server_exp); + return -1; + } + server_bits=ntohl(server_bits); + host_bits=ntohl(host_bits); + protocol_flags=ntohl(protocol_flags); + supported_ciphers_mask=ntohl(supported_ciphers_mask); + supported_authentications_mask=ntohl(supported_authentications_mask); + ssh_say(1,"server bits: %d ; host bits: %d\nProtocol flags : %.8lx ; " + "cipher mask : %.8lx ; auth mask: %.8lx\n",server_bits, + host_bits,protocol_flags,supported_ciphers_mask, + supported_authentications_mask); + serverkey=make_rsa1_string(server_exp,server_mod); + hostkey=make_rsa1_string(host_exp,host_mod); + build_session_id1(session,server_mod,host_mod); + free(server_exp); + free(server_mod); + free(host_exp); + free(host_mod); + svr=publickey_from_string(serverkey); + host=publickey_from_string(hostkey); + session->next_crypto->server_pubkey=string_copy(hostkey); + session->next_crypto->server_pubkey_type="ssh-rsa1"; + + /* now, we must choose an encryption algo */ + /* hardcode 3des */ + if(!(supported_ciphers_mask & (1<out_buffer,SSH_CMSG_SESSION_KEY); + buffer_add_u8(session->out_buffer,SSH_CIPHER_3DES); + buffer_add_data(session->out_buffer,session->server_kex.cookie,8); + + enc_session=encrypt_session_key(session,svr,host); + bits=string_len(enc_session)*8 - 7; + bits=htons(bits); + /* the encrypted mpint */ + buffer_add_data(session->out_buffer,&bits,sizeof(u16)); + buffer_add_data(session->out_buffer,enc_session->string, + string_len(enc_session)); + /* the protocol flags */ + buffer_add_u32(session->out_buffer,0); + + packet_send(session); + /* we can set encryption */ + if(crypt_set_algorithms(session)) + return -1; + session->current_crypto=session->next_crypto; + session->next_crypto=NULL; + if(packet_wait(session,SSH_SMSG_SUCCESS,1)){ + printf("qqchose a merdé: %s\n",ssh_get_error(session)); + exit(1); + return -1; + } + ssh_say(1,"received SSH_SMSG_SUCCESS\n"); + return 0; + +} + diff --git a/libssh/keyfiles.c b/libssh/keyfiles.c new file mode 100644 index 00000000..4891ab5a --- /dev/null +++ b/libssh/keyfiles.c @@ -0,0 +1,344 @@ +/* keyfiles.c */ +/* This part of the library handles private and public key files needed for publickey authentication,*/ +/* as well as servers public hashes verifications and certifications. Lot of code here handles openssh */ +/* implementations (key files aren't standardized yet). */ + +/* +Copyright 2003,04 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libssh/priv.h" +#define MAXLINESIZE 80 + +static int default_get_password(char *buf, int size,int rwflag, char *descr){ + char *pass; + char buffer[256]; + int len; + snprintf(buffer,256,"Please enter passphrase for %s",descr); + pass=getpass(buffer); + snprintf(buf,size,"%s",buffer); + len=strlen(buf); + memset(pass,0,strlen(pass)); + return len; +} + +/* in case the passphrase has been given in parameter */ +static int get_password_specified(char *buf,int size, int rwflag, char *password){ + snprintf(buf,size,"%s",password); + return strlen(buf); +} + +/* TODO : implement it to read both DSA and RSA at once */ +PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,char *passphrase){ + FILE *file=fopen(filename,"r"); + PRIVATE_KEY *privkey; + DSA *dsa=NULL; + RSA *rsa=NULL; + if(!file){ + ssh_set_error(session,SSH_REQUEST_DENIED,"Error opening %s : %s",filename,strerror(errno)); + return NULL; + } + if(type==TYPE_DSS){ + if(!passphrase){ + if(session && session->options->passphrase_function) + dsa=PEM_read_DSAPrivateKey(file,NULL, session->options->passphrase_function,"DSA private key"); + else + dsa=PEM_read_DSAPrivateKey(file,NULL,(void *)default_get_password, "DSA private key"); + } + else + dsa=PEM_read_DSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase); + fclose(file); + if(!dsa){ + ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL)); + return NULL; + } + } + else if (type==TYPE_RSA){ + if(!passphrase){ + if(session && session->options->passphrase_function) + rsa=PEM_read_RSAPrivateKey(file,NULL, session->options->passphrase_function,"RSA private key"); + else + rsa=PEM_read_RSAPrivateKey(file,NULL,(void *)default_get_password, "RSA private key"); + } + else + rsa=PEM_read_RSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase); + fclose(file); + if(!rsa){ + ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL)); + return NULL; + } + } else { + ssh_set_error(session,SSH_FATAL,"Invalid private key type %d",type); + return NULL; + } + + privkey=malloc(sizeof(PRIVATE_KEY)); + privkey->type=type; + privkey->dsa_priv=dsa; + privkey->rsa_priv=rsa; + return privkey; +} + +void private_key_free(PRIVATE_KEY *prv){ + if(prv->dsa_priv) + DSA_free(prv->dsa_priv); + if(prv->rsa_priv) + RSA_free(prv->rsa_priv); + memset(prv,0,sizeof(PRIVATE_KEY)); + free(prv); +} + +STRING *publickey_from_file(SSH_SESSION *session,char *filename,int *_type){ + BUFFER *buffer; + int type; + STRING *str; + char buf[4096]; /* noone will have bigger keys that that */ + /* where have i head that again ? */ + int fd=open(filename,O_RDONLY); + int r; + char *ptr; + if(fd<0){ + ssh_set_error(session,SSH_REQUEST_DENIED,"nonexistent public key file"); + return NULL; + } + if(read(fd,buf,8)!=8){ + close(fd); + ssh_set_error(session,SSH_REQUEST_DENIED,"Invalid public key file"); + return NULL; + } + buf[7]=0; + if(!strcmp(buf,"ssh-dss")) + type=TYPE_DSS; + else if (!strcmp(buf,"ssh-rsa")) + type=TYPE_RSA; + else { + close(fd); + ssh_set_error(session,SSH_REQUEST_DENIED,"Invalid public key file"); + return NULL; + } + r=read(fd,buf,sizeof(buf)-1); + close(fd); + if(r<=0){ + ssh_set_error(session,SSH_REQUEST_DENIED,"Invalid public key file"); + return NULL; + } + buf[r]=0; + ptr=strchr(buf,' '); + if(ptr) + *ptr=0; /* eliminates the garbage at end of file */ + buffer=base64_to_bin(buf); + if(buffer){ + str=string_new(buffer_get_len(buffer)); + string_fill(str,buffer_get(buffer),buffer_get_len(buffer)); + buffer_free(buffer); + if(_type) + *_type=type; + return str; + } else { + ssh_set_error(session,SSH_REQUEST_DENIED,"Invalid public key file"); + return NULL; /* invalid file */ + } +} + + +/* why recursing ? i'll explain. on top, publickey_from_next_file will be executed until NULL returned */ +/* we can't return null if one of the possible keys is wrong. we must test them before getting over */ +STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char **keys_path, + char **privkeyfile,int *type,int *count){ + static char *home=NULL; + char public[256]; + char private[256]; + char *priv; + char *pub; + STRING *pubkey; + if(!home) + home=ssh_get_user_home_dir(); + if(home==NULL) { + ssh_set_error(session,SSH_FATAL,"User home dir impossible to guess"); + return NULL; + } + ssh_set_error(session,SSH_REQUEST_DENIED,"no public key matched"); + if((pub=pub_keys_path[*count])==NULL) + return NULL; + if((priv=keys_path[*count])==NULL) + return NULL; + ++*count; + /* are them readable ? */ + snprintf(public,256,pub,home); + ssh_say(2,"Trying to open %s\n",public); + if(!ssh_file_readaccess_ok(public)){ + ssh_say(2,"Failed\n"); + return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count); + } + snprintf(private,256,priv,home); + ssh_say(2,"Trying to open %s\n",private); + if(!ssh_file_readaccess_ok(private)){ + ssh_say(2,"Failed\n"); + return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count); + } + ssh_say(2,"Okay both files ok\n"); + /* ok, we are sure both the priv8 and public key files are readable : we return the public one as a string, + and the private filename in arguments */ + pubkey=publickey_from_file(session,public,type); + if(!pubkey){ + ssh_say(2,"Wasn't able to open public key file %s : %s\n",public,ssh_get_error(session)); + return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count); + } + *privkeyfile=realloc(*privkeyfile,strlen(private)+1); + strcpy(*privkeyfile,private); + return pubkey; +} + +#define FOUND_OTHER ( (void *)-1) +#define FILE_NOT_FOUND ((void *)-2) +/* will return a token array containing [host,]ip keytype key */ +/* NULL if no match was found, FOUND_OTHER if the match is on an other */ +/* type of key (ie dsa if type was rsa) */ +static char **ssh_parse_knownhost(char *filename, char *hostname, char *type){ + FILE *file=fopen(filename,"r"); + char buffer[4096]; + char *ptr; + char **tokens; + char **ret=NULL; + if(!file) + return FILE_NOT_FOUND; + while(fgets(buffer,sizeof(buffer),file)){ + ptr=strchr(buffer,'\n'); + if(ptr) *ptr=0; + if((ptr=strchr(buffer,'\r'))) *ptr=0; + if(!buffer[0]) + continue; /* skip empty lines */ + tokens=space_tokenize(buffer); + if(!tokens[0] || !tokens[1] || !tokens[2]){ + /* it should have exactly 3 tokens */ + free(tokens[0]); + free(tokens); + continue; + } + if(tokens[3]){ + /* 3 tokens only, not four */ + free(tokens[0]); + free(tokens); + continue; + } + ptr=tokens[0]; + while(*ptr==' ') + ptr++; /* skip the initial spaces */ + /* we allow spaces or ',' to follow the hostname. It's generaly an IP */ + /* we don't care about ip, if the host key match there is no problem with ip */ + if(strncasecmp(ptr,hostname,strlen(hostname))==0){ + if(ptr[strlen(hostname)]==' ' || ptr[strlen(hostname)]=='\0' + || ptr[strlen(hostname)]==','){ + if(strcasecmp(tokens[1],type)==0){ + fclose(file); + return tokens; + } else { + ret=FOUND_OTHER; + } + } + } + /* not the good one */ + free(tokens[0]); + free(tokens); + } + fclose(file); + /* we did not find */ + return ret; +} + +/* public function to test if the server is known or not */ +int ssh_is_server_known(SSH_SESSION *session){ + char *pubkey_64; + BUFFER *pubkey_buffer; + STRING *pubkey=session->current_crypto->server_pubkey; + char **tokens; + ssh_options_default_known_hosts_file(session->options); + if(!session->options->host){ + ssh_set_error(session,SSH_FATAL,"Can't verify host in known hosts if the hostname isn't known"); + return SSH_SERVER_ERROR; + } + tokens=ssh_parse_knownhost(session->options->known_hosts_file, + session->options->host,session->current_crypto->server_pubkey_type); + if(tokens==NULL) + return SSH_SERVER_NOT_KNOWN; + if(tokens==FOUND_OTHER) + return SSH_SERVER_FOUND_OTHER; + if(tokens==FILE_NOT_FOUND){ + ssh_set_error(session,SSH_FATAL,"verifying that server is a known host : file %s not found",session->options->known_hosts_file); + return SSH_SERVER_ERROR; + } + /* ok we found some public key in known hosts file. now un-base64it */ + /* Some time, we may verify the IP address did not change. I honestly think */ + /* it's not an important matter as IP address are known not to be secure */ + /* and the crypto stuff is enough to prove the server's identity */ + pubkey_64=tokens[2]; + pubkey_buffer=base64_to_bin(pubkey_64); + /* at this point, we may free the tokens */ + free(tokens[0]); + free(tokens); + if(!pubkey_buffer){ + ssh_set_error(session,SSH_FATAL,"verifying that server is a known host : base 64 error"); + return SSH_SERVER_ERROR; + } + if(buffer_get_len(pubkey_buffer)!=string_len(pubkey)){ + buffer_free(pubkey_buffer); + return SSH_SERVER_KNOWN_CHANGED; + } + /* now test that they are identical */ + if(memcmp(buffer_get(pubkey_buffer),pubkey->string,buffer_get_len(pubkey_buffer))!=0){ + buffer_free(pubkey_buffer); + return SSH_SERVER_KNOWN_CHANGED; + } + buffer_free(pubkey_buffer); + return SSH_SERVER_KNOWN_OK; +} + +int ssh_write_knownhost(SSH_SESSION *session){ + char *pubkey_64; + STRING *pubkey=session->current_crypto->server_pubkey; + char buffer[4096]; + FILE *file; + ssh_options_default_known_hosts_file(session->options); + if(!session->options->host){ + ssh_set_error(session,SSH_FATAL,"Cannot write host in known hosts if the hostname is unknown"); + return -1; + } + /* a = append only */ + file=fopen(session->options->known_hosts_file,"a"); + if(!file){ + ssh_set_error(session,SSH_FATAL,"Opening known host file %s for appending : %s", + session->options->known_hosts_file,strerror(errno)); + return -1; + } + pubkey_64=bin_to_base64(pubkey->string,string_len(pubkey)); + snprintf(buffer,sizeof(buffer),"%s %s %s\n",session->options->host,session->current_crypto->server_pubkey_type,pubkey_64); + free(pubkey_64); + fwrite(buffer,strlen(buffer),1,file); + fclose(file); + return 0; +} diff --git a/libssh/keys.c b/libssh/keys.c new file mode 100644 index 00000000..16a58db0 --- /dev/null +++ b/libssh/keys.c @@ -0,0 +1,370 @@ +/* keys handle the public key related functions */ +/* decoding a public key (both rsa and dsa), decoding a signature (rsa and dsa), veryfying them */ + +/* +Copyright 2003,04 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ +#include +#include +#include +#include "libssh/priv.h" + + +/* Public key decoding functions */ + +char *ssh_type_to_char(int type){ + switch(type){ + case TYPE_DSS: + return "ssh-dss"; + case TYPE_RSA: + case TYPE_RSA1: + return "ssh-rsa"; + default: + return NULL; + } +} + +PUBLIC_KEY *publickey_make_dss(BUFFER *buffer){ + STRING *p,*q,*g,*pubkey; + PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY)); + key->type=TYPE_DSS; + key->type_c="ssh-dss"; + p=buffer_get_ssh_string(buffer); + q=buffer_get_ssh_string(buffer); + g=buffer_get_ssh_string(buffer); + pubkey=buffer_get_ssh_string(buffer); + buffer_free(buffer); /* we don't need it anymore */ + if(!p || !q || !g || !pubkey){ + ssh_set_error(NULL,SSH_FATAL,"Invalid DSA public key"); + if(p) + free(p); + if(q) + free(q); + if(g) + free(g); + if(pubkey) + free(pubkey); + free(key); + return NULL; + } + key->dsa_pub=DSA_new(); + key->dsa_pub->p=make_string_bn(p); + key->dsa_pub->q=make_string_bn(q); + key->dsa_pub->g=make_string_bn(g); + key->dsa_pub->pub_key=make_string_bn(pubkey); + free(p); + free(q); + free(g); + free(pubkey); + return key; +} + +PUBLIC_KEY *publickey_make_rsa(BUFFER *buffer, char *type){ + STRING *e,*n; + PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY)); + if(!strcmp(type,"ssh-rsa")) + key->type=TYPE_RSA; + else + key->type=TYPE_RSA1; + key->type_c=type; + e=buffer_get_ssh_string(buffer); + n=buffer_get_ssh_string(buffer); + buffer_free(buffer); /* we don't need it anymore */ + if(!e || !n){ + ssh_set_error(NULL,SSH_FATAL,"Invalid RSA public key"); + if(e) + free(e); + if(n) + free(n); + free(key); + return NULL; + } + key->rsa_pub=RSA_new(); + key->rsa_pub->e=make_string_bn(e); + key->rsa_pub->n=make_string_bn(n); +#ifdef DEBUG_CRYPTO + ssh_print_bignum("e",key->rsa_pub->e); + ssh_print_bignum("n",key->rsa_pub->n); +#endif + free(e); + free(n); + return key; +} + +void publickey_free(PUBLIC_KEY *key){ + if(!key) + return; + switch(key->type){ + case TYPE_DSS: + DSA_free(key->dsa_pub); + break; + case TYPE_RSA: + case TYPE_RSA1: + RSA_free(key->rsa_pub); + break; + default: + break; + } + free(key); +} + +PUBLIC_KEY *publickey_from_string(STRING *pubkey_s){ + BUFFER *tmpbuf=buffer_new(); + STRING *type_s; + char *type; + + buffer_add_data(tmpbuf,pubkey_s->string,string_len(pubkey_s)); + type_s=buffer_get_ssh_string(tmpbuf); + if(!type_s){ + buffer_free(tmpbuf); + ssh_set_error(NULL,SSH_FATAL,"Invalid public key format"); + return NULL; + } + type=string_to_char(type_s); + free(type_s); + if(!strcmp(type,"ssh-dss")){ + free(type); + return publickey_make_dss(tmpbuf); + } + if(!strcmp(type,"ssh-rsa")){ + free(type); + return publickey_make_rsa(tmpbuf,"ssh-rsa"); + } + if(!strcmp(type,"ssh-rsa1")){ + free(type); + return publickey_make_rsa(tmpbuf,"ssh-rsa1"); + } + ssh_set_error(NULL,SSH_FATAL,"unknown public key protocol %s",type); + buffer_free(tmpbuf); + free(type); + return NULL; +} + +/* Signature decoding functions */ + +STRING *signature_to_string(SIGNATURE *sign){ + STRING *str; + STRING *rs,*r,*s; + unsigned char buffer[40]; + BUFFER *tmpbuf=buffer_new(); + STRING *tmp; + tmp=string_from_char(ssh_type_to_char(sign->type)); + buffer_add_ssh_string(tmpbuf,tmp); + free(tmp); + switch(sign->type){ + case TYPE_DSS: + r=make_bignum_string(sign->dsa_sign->r); + s=make_bignum_string(sign->dsa_sign->s); + rs=string_new(40); + memset(buffer,0,40); + memcpy(buffer,r->string+string_len(r)-20,20); + memcpy(buffer+ 20, s->string + string_len(s) - 20, 20); + string_fill(rs,buffer,40); + free(r); + free(s); + buffer_add_ssh_string(tmpbuf,rs); + free(rs); + break; + case TYPE_RSA: + case TYPE_RSA1: + buffer_add_ssh_string(tmpbuf,sign->rsa_sign); + break; + } + str=string_new(buffer_get_len(tmpbuf)); + string_fill(str,buffer_get(tmpbuf),buffer_get_len(tmpbuf)); + buffer_free(tmpbuf); + return str; +} + +/* TODO : split this function in two so it becomes smaller */ +SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed_type){ + DSA_SIG *sig; + SIGNATURE *sign=malloc(sizeof(SIGNATURE)); + BUFFER *tmpbuf=buffer_new(); + STRING *rs; + STRING *r,*s,*type_s,*e; + int len,rsalen; + char *type; + buffer_add_data(tmpbuf,signature->string,string_len(signature)); + type_s=buffer_get_ssh_string(tmpbuf); + if(!type_s){ + ssh_set_error(NULL,SSH_FATAL,"Invalid signature packet"); + buffer_free(tmpbuf); + return NULL; + } + type=string_to_char(type_s); + free(type_s); + switch(needed_type){ + case TYPE_DSS: + if(strcmp(type,"ssh-dss")){ + ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type); + buffer_free(tmpbuf); + free(type); + return NULL; + } + break; + case TYPE_RSA: + if(strcmp(type,"ssh-rsa")){ + ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type); + buffer_free(tmpbuf); + free(type); + return NULL; + } + break; + default: + ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type); + free(type); + buffer_free(tmpbuf); + return NULL; + } + free(type); + switch(needed_type){ + case TYPE_DSS: + rs=buffer_get_ssh_string(tmpbuf); + buffer_free(tmpbuf); + if(!rs || string_len(rs)!=40){ /* 40 is the dual signature blob len. */ + if(rs) + free(rs); + return NULL; + } + /* we make use of strings because we have all-made functions to convert them to bignums */ + r=string_new(20); + s=string_new(20); + string_fill(r,rs->string,20); + string_fill(s,rs->string+20,20); + free(rs); + sig=DSA_SIG_new(); + sig->r=make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */ + sig->s=make_string_bn(s); +#ifdef DEBUG_CRYPTO + ssh_print_bignum("r",sig->r); + ssh_print_bignum("s",sig->s); +#endif + free(r); + free(s); + sign->type=TYPE_DSS; + sign->dsa_sign=sig; + return sign; + case TYPE_RSA: + e=buffer_get_ssh_string(tmpbuf); + buffer_free(tmpbuf); + if(!e){ + free(e); + return NULL; + } + len=string_len(e); + rsalen=RSA_size(pubkey->rsa_pub); + if(len>rsalen){ + free(e); + free(sign); + ssh_set_error(NULL,SSH_FATAL,"signature too big ! %d instead of %d",len,rsalen); + return NULL; + } + if(lentype=TYPE_RSA; + sign->rsa_sign=e; +#ifdef DEBUG_CRYPTO + ssh_say(0,"Len : %d\n",len); + ssh_print_hexa("rsa signature",e->string,len); +#endif + return sign; + default: + return NULL; + } +} + +void signature_free(SIGNATURE *sign){ + if(!sign) + return; + switch(sign->type){ + case TYPE_DSS: + DSA_SIG_free(sign->dsa_sign); + break; + case TYPE_RSA: + case TYPE_RSA1: + free(sign->rsa_sign); + break; + default: + ssh_say(1,"freeing a signature with no type !\n"); + } + free(sign); +} + +/* maybe the missing function from libcrypto */ +/* i think now, maybe it's a bad idea to name it has it should have be named in libcrypto */ +static STRING *RSA_do_sign(void *payload,int len,RSA *privkey){ + STRING *sign; + void *buffer=malloc(RSA_size(privkey)); + unsigned int size; + int err; + err=RSA_sign(NID_sha1,payload,len,buffer,&size,privkey); + if(!err){ + free(buffer); + return NULL; + } + sign=string_new(size); + string_fill(sign,buffer,size); + free(buffer); + return sign; +} + +STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, PRIVATE_KEY *privatekey){ + SHACTX *ctx; + STRING *session_str=string_new(SHA_DIGEST_LEN); + char hash[SHA_DIGEST_LEN]; + SIGNATURE *sign; + STRING *signature; + string_fill(session_str,session->current_crypto->session_id,SHA_DIGEST_LENGTH); + ctx=sha1_init(); + sha1_update(ctx,session_str,string_len(session_str)+4); + sha1_update(ctx,buffer_get(sigbuf),buffer_get_len(sigbuf)); + sha1_final(hash,ctx); + free(session_str); + sign=malloc(sizeof(SIGNATURE)); + switch(privatekey->type){ + case TYPE_DSS: + sign->dsa_sign=DSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->dsa_priv); + sign->rsa_sign=NULL; + break; + case TYPE_RSA: + sign->rsa_sign=RSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->rsa_priv); + sign->dsa_sign=NULL; + break; + } + sign->type=privatekey->type; + if(!sign->dsa_sign && !sign->rsa_sign){ + ssh_set_error(session,SSH_FATAL,"Signing : openssl error"); + signature_free(sign); + return NULL; + } + signature=signature_to_string(sign); + signature_free(sign); + return signature; +} + +STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key){ + int len=string_len(data); + int flen=RSA_size(key->rsa_pub); + STRING *ret=string_new(flen); + RSA_public_encrypt(len,data->string,ret->string,key->rsa_pub, + RSA_PKCS1_PADDING); + return ret; +} + diff --git a/libssh/misc.c b/libssh/misc.c new file mode 100644 index 00000000..b9400f7d --- /dev/null +++ b/libssh/misc.c @@ -0,0 +1,98 @@ +/* misc.c */ +/* some misc routines than aren't really part of the ssh protocols but can be useful to the client */ + +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include +#include "libssh/libssh.h" + +/* if the program was executed suid root, don't trust the user ! */ +static int is_trusted(){ + if(geteuid()!=getuid()) + return 0; + return 1; +} + +static char *get_homedir_from_uid(int uid){ + struct passwd *pwd; + char *home; + while((pwd=getpwent())){ + if(pwd->pw_uid == uid){ + home=strdup(pwd->pw_dir); + endpwent(); + return home; + } + } + endpwent(); + return NULL; +} + +static char *get_homedir_from_login(char *user){ + struct passwd *pwd; + char *home; + while((pwd=getpwent())){ + if(!strcmp(pwd->pw_name,user)){ + home=strdup(pwd->pw_dir); + endpwent(); + return home; + } + } + endpwent(); + return NULL; +} + +char *ssh_get_user_home_dir(){ + char *home; + char *user; + int trusted=is_trusted(); + if(trusted){ + if((home=getenv("HOME"))) + return strdup(home); + if((user=getenv("USER"))) + return get_homedir_from_login(user); + } + return get_homedir_from_uid(getuid()); +} + +/* we have read access on file */ +int ssh_file_readaccess_ok(char *file){ + if(!access(file,R_OK)) + return 1; + return 0; +} + + +u64 ntohll(u64 a){ +#ifdef WORDS_BIGENDIAN + return a; +#else + u32 low=a & 0xffffffff; + u32 high = a >> 32 ; + low=ntohl(low); + high=ntohl(high); + return (( ((u64)low) << 32) | ( high)); +#endif +} diff --git a/libssh/options.c b/libssh/options.c new file mode 100644 index 00000000..17d9d3df --- /dev/null +++ b/libssh/options.c @@ -0,0 +1,382 @@ +/* options.c */ +/* handle pre-connection options */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include "libssh/priv.h" + +/* by default, ssh1 support is not allowed */ +SSH_OPTIONS *ssh_options_new(){ + SSH_OPTIONS *option=malloc(sizeof(SSH_OPTIONS)); + memset(option,0,sizeof(SSH_OPTIONS)); + option->port=22; /* set the default port */ + option->fd=-1; + option->ssh2allowed=1; + option->ssh1allowed=0; + return option; +} + +void ssh_options_set_port(SSH_OPTIONS *opt, unsigned int port){ + opt->port=port&0xffff; +} +SSH_OPTIONS *ssh_options_copy(SSH_OPTIONS *opt){ + SSH_OPTIONS *ret=ssh_options_new(); + int i; + ret->fd=opt->fd; + ret->port=opt->port; + if(opt->username) + ret->username=strdup(opt->username); + if(opt->host) + ret->host=strdup(opt->host); + if(opt->bindaddr) + ret->host=strdup(opt->bindaddr); + if(opt->identity) + ret->identity=strdup(opt->identity); + if(opt->ssh_dir) + ret->ssh_dir=strdup(opt->ssh_dir); + if(opt->known_hosts_file) + ret->known_hosts_file=strdup(opt->known_hosts_file); + for(i=0;i<10;++i) + if(opt->wanted_methods[i]) + ret->wanted_methods[i]=strdup(opt->wanted_methods[i]); + ret->passphrase_function=opt->passphrase_function; + ret->connect_status_function=opt->connect_status_function; + ret->connect_status_arg=opt->connect_status_arg; + ret->timeout=opt->timeout; + ret->timeout_usec=opt->timeout_usec; + ret->ssh2allowed=opt->ssh2allowed; + ret->ssh1allowed=opt->ssh1allowed; + return ret; +} + +void ssh_options_free(SSH_OPTIONS *opt){ + int i; + if(opt->username) + free(opt->username); + if(opt->identity) + free(opt->identity); + /* we don't touch the banner. if the implementation did use it, they have to free it */ + if(opt->host) + free(opt->host); + if(opt->bindaddr) + free(opt->bindaddr); + if(opt->ssh_dir) + free(opt->ssh_dir); + for(i=0;i<10;i++) + if(opt->wanted_methods[i]) + free(opt->wanted_methods[i]); + memset(opt,0,sizeof(SSH_OPTIONS)); + free(opt); +} + + +void ssh_options_set_host(SSH_OPTIONS *opt, const char *hostname){ + char *ptr=strdup(hostname); + char *ptr2=strchr(ptr,'@'); + if(opt->host) // don't leak memory + free(opt->host); + if(ptr2){ + *ptr2=0; + opt->host=strdup(ptr2+1); + if(opt->username) + free(opt->username); + opt->username=strdup(ptr); + free(ptr); + } else + opt->host=ptr; +} + +void ssh_options_set_username(SSH_OPTIONS *opt, char *username){ + if(opt->username) + free(opt->username); + opt->username=strdup(username); +} + +void ssh_options_set_fd(SSH_OPTIONS *opt, int fd){ + opt->fd=fd; +} + +void ssh_options_set_bind(SSH_OPTIONS *opt, char *bindaddr,int port){ + opt->bindaddr=strdup(bindaddr); + opt->bindport=port; +} + +void ssh_options_set_ssh_dir(SSH_OPTIONS *opt, char *dir){ + char buffer[1024]; + snprintf(buffer,1024,dir,ssh_get_user_home_dir()); + opt->ssh_dir=strdup(buffer); +} + +void ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir){ + char buffer[1024]; + snprintf(buffer,1024,dir,ssh_get_user_home_dir()); + opt->known_hosts_file=strdup(buffer); +} + +void ssh_options_set_identity(SSH_OPTIONS *opt, char *identity){ + char buffer[1024]; + snprintf(buffer,1024,identity,ssh_get_user_home_dir()); + opt->identity=strdup(buffer); +} + +void ssh_options_set_banner(SSH_OPTIONS *opt, char *banner){ + if(opt->banner) + free(opt->banner); + opt->banner=strdup(banner); +} + +/* what's the deal here ? some options MUST be set before authentication or key exchange, + * otherwise default values are going to be used. what must be configurable : + * Public key certification method * + * key exchange method (dh-sha1 for instance)* + * c->s, s->c ciphers * + * c->s s->c macs * + * c->s s->c compression */ + +/* they all return 0 if all went well, 1 or !=0 if not. the most common error is unmatched algo (unimplemented) */ +/* don't forget other errors can happen if no matching algo is found in sshd answer */ + +#warning ssh_options_get_supported_algos + +int ssh_options_set_wanted_algos(SSH_OPTIONS *opt,int algo, char *list){ + if(algo > SSH_LANG_S_C || algo < 0){ + ssh_set_error(NULL,SSH_REQUEST_DENIED,"algo %d out of range",algo); + return -1; + } + if( (!opt->use_nonexisting_algo) && !verify_existing_algo(algo,list)){ + ssh_set_error(NULL,SSH_REQUEST_DENIED,"Setting method : no algorithm " + "for method \"%s\" (%s)\n",ssh_kex_nums[algo],list); + return -1; + } + if(opt->wanted_methods[algo]) + free(opt->wanted_methods[algo]); + opt->wanted_methods[algo]=strdup(list); + return 0; +} + +static char *get_username_from_uid(int uid){ + struct passwd *pwd; + char *user; + while((pwd=getpwent())){ + if(pwd->pw_uid == uid){ + user=strdup(pwd->pw_name); + endpwent(); + return user; + } + } + endpwent(); + ssh_set_error(NULL,SSH_FATAL,"uid %d doesn't exist !",uid); + return NULL; +} + +/* this function must be called when no specific username has been asked. it has to guess it */ +int ssh_options_default_username(SSH_OPTIONS *opt){ + char *user; + if(opt->username) + return 0; + user=getenv("USER"); + if(user){ + opt->username=strdup(user); + return 0; + } + user=get_username_from_uid(getuid()); + if(user){ + opt->username=user; + return 0; + } + return -1; +} + +int ssh_options_default_ssh_dir(SSH_OPTIONS *opt){ + char buffer[256]; + if(opt->ssh_dir) + return 0; + snprintf(buffer,256,"%s/.ssh/",ssh_get_user_home_dir()); + opt->ssh_dir=strdup(buffer); + return 0; +} + +int ssh_options_default_known_hosts_file(SSH_OPTIONS *opt){ + char buffer[1024]; + if(opt->known_hosts_file) + return 0; + ssh_options_default_ssh_dir(opt); + snprintf(buffer,1024,"%s/known_hosts",opt->ssh_dir); + opt->known_hosts_file=strdup(buffer); + return 0; +} + +void ssh_options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg ){ + opt->connect_status_function=callback; + opt->connect_status_arg=arg; +} + +void ssh_options_set_timeout(SSH_OPTIONS *opt, long seconds,long usec){ + opt->timeout=seconds; + opt->timeout_usec=usec; +} + +void ssh_options_allow_ssh1(SSH_OPTIONS *opt, int allow){ + if(allow) + opt->ssh1allowed=1; + else + opt->ssh1allowed=0; +} + +void ssh_options_allow_ssh2(SSH_OPTIONS *opt, int allow){ + if(allow) + opt->ssh2allowed=1; + else + opt->ssh2allowed=0; +} + +int ssh_options_getopt(SSH_OPTIONS *options, int *argcptr, char **argv){ + int i; + int argc=*argcptr; + char *user=NULL; + int port=22; + int debuglevel=0; + int usersa=0; + int usedss=0; + int compress=0; + int cont=1; + char *cipher=NULL; + char *localaddr=NULL; + char *identity=NULL; + char **save=malloc(argc * sizeof(char *)); + int current=0; + int ssh1=0; + int ssh2=1; + + int saveoptind=optind; /* need to save 'em */ + int saveopterr=opterr; + opterr=0; /* shut up getopt */ + while(cont && ((i=getopt(argc,argv,"c:i:Cl:p:vb:rd12"))!=-1)){ + + switch(i){ + case 'l': + user=optarg; + break; + case 'p': + port=atoi(optarg)&0xffff; + break; + case 'v': + debuglevel++; + break; + case 'r': + usersa++; + break; + case 'd': + usedss++; + break; + case 'c': + cipher=optarg; + break; + case 'i': + identity=optarg; + break; + case 'b': + localaddr=optarg; + break; + case 'C': + compress++; + break; + case '2': + ssh2=1; + ssh1=0; + break; + case '1': + ssh2=0; + ssh1=1; + break; + default: + { + char opt[3]="- "; + opt[1]=optopt; + save[current++]=strdup(opt); + if(optarg) + save[current++]=argv[optind+1]; + } + } + } + opterr=saveopterr; + while(optind < argc) + save[current++]=argv[optind++]; + + if(usersa && usedss){ + ssh_set_error(NULL,SSH_FATAL,"either RSA or DSS must be chosen"); + cont=0; + } + ssh_set_verbosity(debuglevel); + optind=saveoptind; + if(!cont){ + free(save); + return -1; + } + /* first recopy the save vector into original's */ + for(i=0;i +#include +#include +#include +#include "libssh/priv.h" +#include "libssh/ssh2.h" +#include "libssh/ssh1.h" +#include +#include +#include "libssh/crypto.h" + +/* XXX include selected mac size */ +static int macsize=SHA_DIGEST_LENGTH; + +/* completeread will read blocking until len bytes have been read */ +static int completeread(int fd, void *buffer, int len){ + int r; + int total=0; + int toread=len; + while((r=read(fd,buffer+total,toread))){ + if(r==-1) + return -1; + total += r; + toread-=r; + if(total==len) + return len; + if(r==0) + return 0; + } + return total ; /* connection closed */ +} + +static int packet_read2(SSH_SESSION *session){ + u32 len; + void *packet=NULL; + char mac[30]; + char buffer[16]; + int be_read,i; + int to_be_read; + u8 padding; + unsigned int blocksize=(session->current_crypto?session->current_crypto->in_cipher->blocksize:8); + session->data_to_read=0; /* clear the dataavailable flag */ + memset(&session->in_packet,0,sizeof(PACKET)); + if(session->in_buffer) + buffer_free(session->in_buffer); + session->in_buffer=buffer_new(); + + be_read=completeread(session->fd,buffer,blocksize); + if(be_read!=blocksize){ + if(be_read<=0){ + session->alive=0; + close(session->fd); + session->fd=-1; + ssh_set_error(session,SSH_FATAL, + (be_read==0)?"Connection closed by remote host" : "Error reading socket"); + return -1; + } + ssh_set_error(session,SSH_FATAL,"read_packet(): asked %d bytes, received %d",blocksize,be_read); + return -1; + } + len=packet_decrypt_len(session,buffer); + buffer_add_data(session->in_buffer,buffer,blocksize); + + if(len> MAX_PACKET_LEN){ + ssh_set_error(session,SSH_FATAL,"read_packet(): Packet len too high(%uld %.8lx)",len,len); + return -1; + } + to_be_read=len-be_read+sizeof(u32); + if(to_be_read<0){ + /* remote sshd is trying to get me ?*/ + ssh_set_error(session,SSH_FATAL,"given numbers of bytes left to be read <0 (%d)!",to_be_read); + return -1; + } + /* handle the case in which the whole packet size = blocksize */ + if(to_be_read !=0){ + packet=malloc(to_be_read); + i=completeread(session->fd,packet,to_be_read); + if(i<=0){ + session->alive=0; + close(session->fd); + session->fd=-1; + ssh_set_error(session,SSH_FATAL,"Server closed connection"); + return -1; + } + if(i!=to_be_read){ + free(packet); + packet=NULL; + ssh_say(3,"Read only %d, wanted %d\n",i,to_be_read); + ssh_set_error(session,SSH_FATAL,"read_packet(): read only %d, wanted %d",i,to_be_read); + return -1; + } + ssh_say(3,"Read a %d bytes packet\n",len); + buffer_add_data(session->in_buffer,packet,to_be_read); + free(packet); + } + if(session->current_crypto){ + packet_decrypt(session,buffer_get(session->in_buffer)+blocksize,buffer_get_len(session->in_buffer)-blocksize); + if((i=completeread(session->fd,mac,macsize))!=macsize){ + if(i<=0){ + session->alive=0; + close(session->fd); + session->fd=-1; + ssh_set_error(session,SSH_FATAL,"Server closed connection"); + return -1; + } + ssh_set_error(session,SSH_FATAL,"read_packet(): wanted %d, had %d",i,macsize); + return -1; + } + if(packet_hmac_verify(session,session->in_buffer,mac)){ + ssh_set_error(session,SSH_FATAL,"HMAC error"); + return -1; + } + } + buffer_pass_bytes(session->in_buffer,sizeof(u32)); /*pass the size which has been processed before*/ + if(!buffer_get_u8(session->in_buffer,&padding)){ + ssh_set_error(session,SSH_FATAL,"Packet too short to read padding"); + return -1; + } + ssh_say(3,"%hhd bytes padding\n",padding); + if(padding > buffer_get_rest_len(session->in_buffer)){ + ssh_set_error(session,SSH_FATAL,"invalid padding: %d (%d resting)",padding,buffer_get_rest_len(session->in_buffer)); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("incrimined packet",buffer_get(session->in_buffer),buffer_get_len(session->in_buffer)); +#endif + return -1; + } + buffer_pass_bytes_end(session->in_buffer,padding); +#ifdef HAVE_LIBZ + if(session->current_crypto && session->current_crypto->do_compress_in){ + decompress_buffer(session,session->in_buffer); + } +#endif + session->recv_seq++; + return 0; +} + +#ifdef HAVE_SSH1 +/* a slighty modified packet_read2() for SSH-1 protocol */ +static int packet_read1(SSH_SESSION *session){ + u32 len; + void *packet=NULL; +// char buffer[16]; + int be_read,i; + int to_be_read; + u32 padding; + u32 crc; + ssh_say(3,"packet_read1()\n"); +// unsigned int blocksize=8; + session->data_to_read=0; /* clear the dataavailable flag */ + memset(&session->in_packet,0,sizeof(PACKET)); + if(session->in_buffer) + buffer_free(session->in_buffer); + session->in_buffer=buffer_new(); + + be_read=completeread(session->fd,&len,sizeof(u32)); + if(be_read!=sizeof(u32)){ + if(be_read<=0){ + session->alive=0; + close(session->fd); + session->fd=-1; + ssh_set_error(session,SSH_FATAL, + (be_read==0)?"Connection closed by remote host" : "Error reading socket"); + return -1; + } + ssh_set_error(session,SSH_FATAL,"read_packet(): asked %d bytes, received %d",sizeof(u32),be_read); + return -1; + } + /* len is not encrypted */ + len=ntohl(len); + + if(len> MAX_PACKET_LEN){ + ssh_set_error(session,SSH_FATAL,"read_packet(): Packet len too high(%uld %.8lx)",len,len); + return -1; + } + ssh_say(3,"%d bytes packet\n",len); + /* SSH-1 has a fixed padding lenght */ + padding=8-(len % 8); + to_be_read=len+padding; + /* handle the case in which the whole packet size = blocksize */ + if(to_be_read !=0){ + packet=malloc(to_be_read); + i=completeread(session->fd,packet,to_be_read); + if(i<=0){ + session->alive=0; + close(session->fd); + session->fd=-1; + ssh_set_error(session,SSH_FATAL,"Server closed connection"); + return -1; + } + if(i!=to_be_read){ + free(packet); + packet=NULL; + ssh_say(3,"Read only %d, wanted %d\n",i,to_be_read); + ssh_set_error(session,SSH_FATAL,"read_packet(): read only %d, wanted %d",i,to_be_read); + return -1; + } + ssh_say(3,"Read a %d bytes packet\n",len); + buffer_add_data(session->in_buffer,packet,to_be_read); + free(packet); + } +#ifdef DEBUG_CRYPTO + ssh_print_hexa("read packet:",buffer_get(session->in_buffer), + buffer_get_len(session->in_buffer)); +#endif + if(session->current_crypto){ + /* we decrypt everything, missing the lenght part (which was previously + * read, unencrypted, and is not part of the buffer + */ + packet_decrypt(session,buffer_get(session->in_buffer),buffer_get_len(session->in_buffer)); + } +#ifdef DEBUG_CRYPTO +ssh_print_hexa("read packet decrypted:",buffer_get(session->in_buffer),buffer_get_len(session->in_buffer)); +#endif + ssh_say(3,"%d bytes padding\n",padding); + if((len+padding) != buffer_get_rest_len(session->in_buffer) || (len+padding) < sizeof(u32)){ + ssh_say(2,"no crc32 in packet\n"); + ssh_set_error(session,SSH_FATAL,"no crc32 in packet"); + return -1; + } + memcpy(&crc,buffer_get_rest(session->in_buffer)+(len+padding)-sizeof(u32), + sizeof(u32)); + buffer_pass_bytes_end(session->in_buffer,sizeof(u32)); + crc=ntohl(crc); + if(ssh_crc32(buffer_get_rest(session->in_buffer),(len+padding)-sizeof(u32))!=crc){ +#ifdef DEBUG_CRYPTO + ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer), + len + padding - sizeof(u32)); +#endif + ssh_say(2,"invalid crc32\n"); + ssh_set_error(session,SSH_FATAL,"invalid crc32 : expected %.8lx, " + "got %.8lx",crc, + ssh_crc32(buffer_get_rest(session->in_buffer),len+padding-sizeof(u32)) ); + return -1; + } + buffer_pass_bytes(session->in_buffer,padding); /*pass the padding*/ + ssh_say(3,"the packet is valid\n"); +/* will do that later +#ifdef HAVE_LIBZ + if(session->current_crypto && session->current_crypto->do_compress_in){ + decompress_buffer(session,session->in_buffer); + } +#endif +*/ + session->recv_seq++; + return 0; +} + +#endif /* HAVE_SSH1 */ + +/* that's where i'd like C to be object ... */ +int packet_read(SSH_SESSION *session){ +#ifdef HAVE_SSH1 + if(session->version==1) + return packet_read1(session); + else +#endif + return packet_read2(session); +} + +int packet_translate(SSH_SESSION *session){ + memset(&session->in_packet,0,sizeof(PACKET)); + if(!session->in_buffer) + return -1; + ssh_say(3,"Final size %d\n",buffer_get_rest_len(session->in_buffer)); + if(!buffer_get_u8(session->in_buffer,&session->in_packet.type)){ + ssh_set_error(session,SSH_FATAL,"Packet too short to read type"); + return -1; + } + ssh_say(3,"type %hhd\n",session->in_packet.type); + session->in_packet.valid=1; + return 0; +} + +static int atomic_write(int fd, void *buffer, int len){ + int written; + int total=0; + do { + written=write(fd,buffer,len); + if(written==0) + return 0; + if(written==-1) + return total; + total+=written; + len-=written; + buffer+=written; + } while (len > 0); + return total; +} + +static int packet_send2(SSH_SESSION *session){ + char padstring[32]; + u32 finallen; + u8 padding; + u32 currentlen=buffer_get_len(session->out_buffer); + char *hmac; + int ret=0; + unsigned int blocksize=(session->current_crypto?session->current_crypto->out_cipher->blocksize:8); + ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen); +#ifdef HAVE_LIBZ + if(session->current_crypto && session->current_crypto->do_compress_out){ + compress_buffer(session,session->out_buffer); + currentlen=buffer_get_len(session->out_buffer); + } +#endif + padding=(blocksize- ((currentlen+5) % blocksize)); + if(padding<4) + padding+=blocksize; + if(session->current_crypto) + ssh_get_random(padstring,padding); + else + memset(padstring,0,padding); + finallen=htonl(currentlen+padding+1); + ssh_say(3,",%d bytes after comp + %d padding bytes = %d bytes packet\n",currentlen,padding,(ntohl(finallen))); + buffer_add_data_begin(session->out_buffer,&padding,sizeof(u8)); + buffer_add_data_begin(session->out_buffer,&finallen,sizeof(u32)); + buffer_add_data(session->out_buffer,padstring,padding); + hmac=packet_encrypt(session,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer)); + if(hmac) + buffer_add_data(session->out_buffer,hmac,20); + if(atomic_write(session->fd,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer))!=buffer_get_len(session->out_buffer)){ + session->alive=0; + close(session->fd); + session->fd=-1; + ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s", + strerror(errno)); + ret=-1; + } + session->send_seq++; + buffer_reinit(session->out_buffer); + return ret; +} + +#ifdef HAVE_SSH1 +static int packet_send1(SSH_SESSION *session){ + char padstring[32]; + u32 finallen; + u8 padding; + u32 crc; + u32 currentlen=buffer_get_len(session->out_buffer)+sizeof(u32); + int ret=0; + unsigned int blocksize=(session->current_crypto?session->current_crypto->out_cipher->blocksize:8); + ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen); +/* +#ifdef HAVE_LIBZ + if(session->current_crypto && session->current_crypto->do_compress_out){ + compress_buffer(session,session->out_buffer); + currentlen=buffer_get_len(session->out_buffer); + } +#endif +*/ + padding=blocksize-(currentlen % blocksize); + if(session->current_crypto) + ssh_get_random(padstring,padding); + else + memset(padstring,0,padding); + finallen=htonl(currentlen); + ssh_say(3,",%d bytes after comp + %d padding bytes = %d bytes packet\n",currentlen,padding,(ntohl(finallen))); + buffer_add_data_begin(session->out_buffer,&padstring,padding); + buffer_add_data_begin(session->out_buffer,&finallen,sizeof(u32)); + crc=ssh_crc32(buffer_get(session->out_buffer)+sizeof(u32),buffer_get_len(session->out_buffer)-sizeof(u32)); + buffer_add_u32(session->out_buffer,ntohl(crc)); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("clear packet",buffer_get(session->out_buffer), + buffer_get_len(session->out_buffer)); +#endif + packet_encrypt(session,buffer_get(session->out_buffer)+sizeof(u32),buffer_get_len(session->out_buffer)-sizeof(u32)); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer), + buffer_get_len(session->out_buffer)); +#endif + if(atomic_write(session->fd,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer))!=buffer_get_len(session->out_buffer)){ + session->alive=0; + close(session->fd); + session->fd=-1; + ssh_set_error(session,SSH_FATAL,"Writing packet : error on socket (or connection closed): %s", + strerror(errno)); + ret=-1; + } + session->send_seq++; + buffer_reinit(session->out_buffer); + return ret; +} + +#endif /* HAVE_SSH1 */ + +int packet_send(SSH_SESSION *session){ +#ifdef HAVE_SSH1 + if (session->version==1) + return packet_send1(session); + else +#endif + return packet_send2(session); +} + +void packet_parse(SSH_SESSION *session){ + int type=session->in_packet.type; + u32 foo; + STRING *error_s; + char *error=NULL; +#ifdef HAVE_SSH1 + if(session->version==1){ + /* SSH-1 */ + switch(type){ + case SSH_MSG_DISCONNECT: + ssh_say(2,"Received SSH_MSG_DISCONNECT\n"); + ssh_set_error(session,SSH_FATAL,"Received SSH_MSG_DISCONNECT"); + close(session->fd); + session->fd=-1; + session->alive=0; + return; + case SSH_SMSG_STDOUT_DATA: + case SSH_SMSG_STDERR_DATA: + case SSH_SMSG_EXITSTATUS: + channel_handle1(session,type); + return; + default: + ssh_say(2,"Unexpected message code %d\n",type); + } + return; + } else { +#endif /* HAVE_SSH1 */ + switch(type){ + case SSH2_MSG_DISCONNECT: + buffer_get_u32(session->in_buffer,&foo); + error_s=buffer_get_ssh_string(session->in_buffer); + if(error_s) + error=string_to_char(error_s); + ssh_say(2,"Received SSH_MSG_DISCONNECT\n"); + ssh_set_error(session,SSH_FATAL,"Received SSH_MSG_DISCONNECT : %s",error); + if(error_s){ + free(error_s); + free(error); + } + close(session->fd); + session->fd=-1; + session->alive=0; + return; + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + case SSH2_MSG_CHANNEL_DATA: + case SSH2_MSG_CHANNEL_EXTENDED_DATA: + case SSH2_MSG_CHANNEL_REQUEST: + case SSH2_MSG_CHANNEL_EOF: + case SSH2_MSG_CHANNEL_CLOSE: + + channel_handle(session,type); + case SSH2_MSG_IGNORE: + return; + default: + ssh_say(0,"Received unhandled msg %d\n",type); + } +#ifdef HAVE_SSH1 + } +#endif +} + +#ifdef HAVE_SSH1 +static int packet_wait1(SSH_SESSION *session,int type,int blocking){ + ssh_say(3,"packet_wait1 waiting for %d\n",type); + while(1){ + if(packet_read1(session)) + return -1; + if(packet_translate(session)) + return -1; + ssh_say(3,"packet_wait 1 received %d\n",session->in_packet.type); + switch(session->in_packet.type){ + case SSH_MSG_DISCONNECT: + packet_parse(session); + return -1; + case SSH_SMSG_STDOUT_DATA: + case SSH_SMSG_STDERR_DATA: + case SSH_SMSG_EXITSTATUS: + channel_handle1(session,type); + break; +/* case SSH2_MSG_CHANNEL_CLOSE: + packet_parse(session); + break;; + case SSH2_MSG_IGNORE: + break; +*/ + default: + if(type && (type != session->in_packet.type)){ + ssh_set_error(session,SSH_FATAL,"waitpacket(): Received a %d type packet, was waiting for a %d\n",session->in_packet.type,type); + return -1; + } + return 0; + } + if(blocking==0) + return 0; + } + return 0; +} +#endif /* HAVE_SSH1 */ +static int packet_wait2(SSH_SESSION *session,int type,int blocking){ + while(1){ + if(packet_read2(session)) + return -1; + if(packet_translate(session)) + return -1; + switch(session->in_packet.type){ + case SSH2_MSG_DISCONNECT: + packet_parse(session); + return -1; + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + case SSH2_MSG_CHANNEL_DATA: + case SSH2_MSG_CHANNEL_EXTENDED_DATA: + case SSH2_MSG_CHANNEL_REQUEST: + case SSH2_MSG_CHANNEL_EOF: + case SSH2_MSG_CHANNEL_CLOSE: + packet_parse(session); + break;; + case SSH2_MSG_IGNORE: + break; + default: + if(type && (type != session->in_packet.type)){ + ssh_set_error(session,SSH_FATAL,"waitpacket(): Received a %d type packet, was waiting for a %d\n",session->in_packet.type,type); + return -1; + } + return 0; + } + if(blocking==0) + return 0; + } + return 0; +} +int packet_wait(SSH_SESSION *session, int type, int block){ +#ifdef HAVE_SSH1 + if(session->version==1) + return packet_wait1(session,type,block); + else +#endif + return packet_wait2(session,type,block); +} + + +void packet_clear_out(SSH_SESSION *session){ + if(session->out_buffer) + buffer_reinit(session->out_buffer); + else + session->out_buffer=buffer_new(); +} + diff --git a/libssh/server.c b/libssh/server.c new file mode 100644 index 00000000..8bfe209d --- /dev/null +++ b/libssh/server.c @@ -0,0 +1,128 @@ +/* server.c */ + +/* No. It doesn't work yet. It's just hard to have 2 separated trees, one for releases + * and one for development */ +/* +Copyright 2004 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* from times to times, you need to serve your friends */ +/* and, perhaps, ssh connections. */ + +#ifdef WITH_SERVER + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libssh/libssh.h" +#include "libssh/server.h" + +int bind_socket() { + struct sockaddr_in myaddr; + int opt = 1; + int s = socket(PF_INET, SOCK_STREAM, 0); + memset(&myaddr, 0, sizeof(myaddr)); + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2222); + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) { + ssh_set_error(NULL, SSH_FATAL, "%s", strerror(errno)); + return -1; + } + /* ok, bound */ + return s; +} + +int listen_socket(int socket) { + int i = listen(socket, 1); + if (i < 0) + ssh_set_error(NULL, SSH_FATAL, "listening on %d : %s", + strerror(errno)); + return i; +} + +int accept_socket(int socket) { + int i = accept(socket, NULL, NULL); + if (i < 0) + ssh_set_error(NULL, SSH_FATAL, "accepting client on socket %d : %s", + strerror(errno)); + return i; +} + + +SSH_SESSION *getserver(SSH_OPTIONS * options) { + int socket; + int fd; + SSH_SESSION *session; + socket = bind_socket(); + if (socket < 0) + return NULL; + if (listen_socket(socket) < 0) + return NULL; + fd = accept_socket(socket); + close(socket); + if (fd < 0) { + return NULL; + } + session = malloc(sizeof(SSH_SESSION)); + memset(session, 0, sizeof(SSH_SESSION)); + session->fd = fd; + session->options = options; + ssh_send_banner(session); + return session; +} + +extern char *supported_methods[]; +int server_set_kex(SSH_SESSION * session) { + KEX *server = &session->server_kex; + SSH_OPTIONS *options = session->options; + int i; + char *wanted; + if (!options) { + ssh_set_error(session, SSH_FATAL, + "Options structure is null(client's bug)"); + return -1; + } + memset(server,0,sizeof(KEX)); + /* the program might ask for a specific cookie to be sent. useful for server + debugging */ + if (options->wanted_cookie) + memcpy(server->cookie, options->wanted_cookie, 16); + else + ssh_get_random(server->cookie, 16); + server->methods = malloc(10 * sizeof(char **)); + for (i = 0; i < 10; i++) { + if (!(wanted = options->wanted_methods[i])) + wanted = supported_methods[i]; + server->methods[i] = wanted; + printf("server->methods[%d]=%s\n",i,wanted); + if (!server->methods[i]) { + ssh_set_error(session, SSH_FATAL, + "kex error : did not find algo"); + return -1; + } + return 0; +} + +#endif /* HAVE_SERVER */ diff --git a/libssh/session.c b/libssh/session.c new file mode 100644 index 00000000..bfc6e58e --- /dev/null +++ b/libssh/session.c @@ -0,0 +1,124 @@ +/* session.c */ +/* contains the non-networking functions ssh_* */ +/* + * Copyright 2005 Aris Adamantiadis + * + * This file is part of the SSH Library + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. */ + +/* ssh_new() returns a newly allocated SSH_SESSION structure pointer */ +#include +#include "libssh/libssh.h" +#include "libssh/priv.h" + +#define FIRST_CHANNEL 42 // why not ? it helps to find bugs. + +SSH_SESSION *ssh_new() { + SSH_SESSION *session=malloc(sizeof (SSH_SESSION)); + memset(session,0,sizeof(SSH_SESSION)); + session->next_crypto=crypto_new(); + session->maxchannel=FIRST_CHANNEL; + return session; +} + +void ssh_cleanup(SSH_SESSION *session){ + int i; + if(session->serverbanner) + free(session->serverbanner); + if(session->clientbanner) + free(session->clientbanner); + if(session->in_buffer) + buffer_free(session->in_buffer); + if(session->out_buffer) + buffer_free(session->out_buffer); + if(session->banner) + free(session->banner); + if(session->options) + ssh_options_free(session->options); + if(session->current_crypto) + crypto_free(session->current_crypto); + if(session->next_crypto) + crypto_free(session->next_crypto); + + // delete all channels + while(session->channels) + channel_free(session->channels); + if(session->client_kex.methods) + for(i=0;i<10;i++) + if(session->client_kex.methods[i]) + free(session->client_kex.methods[i]); + if(session->server_kex.methods) + for(i=0;i<10;++i) + if(session->server_kex.methods[i]) + free(session->server_kex.methods[i]); + free(session->client_kex.methods); + free(session->server_kex.methods); + memset(session,'X',sizeof(SSH_SESSION)); /* burn connection, it could hangs + sensitive datas */ + free(session); +} + +void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options){ + session->options=options; +} + +void ssh_set_blocking(SSH_SESSION *session,int blocking){ + session->blocking=blocking?1:0; +} + +int ssh_get_fd(SSH_SESSION *session){ + return session->fd; +} + +void ssh_set_fd_toread(SSH_SESSION *session){ + session->data_to_read=1; +} + +void ssh_set_fd_towrite(SSH_SESSION *session){ + session->data_to_write=1; +} + +void ssh_set_fd_except(SSH_SESSION *session){ + session->data_except=1; +} + +int ssh_get_status(SSH_SESSION *session){ + int ret=0; + if(session->closed) + ret |= SSH_CLOSED; + if(session->channel_bytes_toread > 0 || session->data_to_read) + ret |= SSH_READ_PENDING; + if(session->closed && session->closed_by_except) + ret |= SSH_CLOSED_ERROR; + return ret; +} + +const char *ssh_get_disconnect_message(SSH_SESSION *session){ + if(!session->closed) + ssh_set_error(session,SSH_REQUEST_DENIED,"Connection not closed" + " yet"); + else if(session->closed_by_except) + ssh_set_error(session,SSH_REQUEST_DENIED,"Connection closed by " + "socket error"); + else if(!session->discon_msg) + ssh_set_error(session,SSH_FATAL,"Connection correctly closed but " + "no disconnect message"); + else + return session->discon_msg; + return NULL; +} + diff --git a/libssh/sftp.c b/libssh/sftp.c new file mode 100644 index 00000000..4135e5bc --- /dev/null +++ b/libssh/sftp.c @@ -0,0 +1,1290 @@ +/* scp.c contains the needed function to work with file transfer protocol over ssh*/ +/* don't look further if you believe this is just FTP over some tunnel. It IS different */ +/* This file contains code written by Nick Zitzmann */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + + +#include +#include +#include +#include "libssh/priv.h" +#include "libssh/ssh2.h" +#include "libssh/sftp.h" +#ifndef NO_SFTP +/* here how it works : sftp commands are channeled by the ssh sftp subsystem. */ +/* every packet are sent/read using a SFTP_PACKET type structure. */ +/* into these packets, most of the server answers are messages having an ID and */ +/* having a message specific part. it is described by SFTP_MESSAGE */ +/* when reading a message, the sftp system puts it into the queue, so the process having asked for it */ +/* can fetch it, while continuing to read for other messages (it is inspecified in which order messages may */ +/* be sent back to the client */ + + +/* functions */ +static void sftp_packet_free(SFTP_PACKET *packet); +void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg); +static void sftp_message_free(SFTP_MESSAGE *msg); + +SFTP_SESSION *sftp_new(SSH_SESSION *session){ + SFTP_SESSION *sftp=malloc(sizeof(SFTP_SESSION)); + memset(sftp,0,sizeof(SFTP_SESSION)); + sftp->session=session; + sftp->channel=channel_new(session); + if(channel_open_session(sftp->channel)){ + channel_free(sftp->channel); + free(sftp); + return NULL; + } + if(channel_request_sftp(sftp->channel)){ + sftp_free(sftp); + return NULL; + } + return sftp; +} + +void sftp_free(SFTP_SESSION *sftp){ + struct request_queue *ptr; + channel_send_eof(sftp->channel); + channel_free(sftp->channel); + ptr=sftp->queue; + while(ptr){ + struct request_queue *old; + sftp_message_free(ptr->message); + old=ptr->next; + free(ptr); + ptr=old; + } + memset(sftp,0,sizeof(*sftp)); + free(sftp); +} + +int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload){ + u32 size; + buffer_add_data_begin(payload,&type,sizeof(u8)); + size=htonl(buffer_get_len(payload)); + buffer_add_data_begin(payload,&size,sizeof(u32)); + size=channel_write(sftp->channel,buffer_get(payload),buffer_get_len(payload)); + if(size != buffer_get_len(payload)){ + ssh_say(1,"had to write %d bytes, wrote only %d\n",buffer_get_len(payload),size); + } + return size; +} + +SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp){ + SFTP_PACKET *packet=malloc(sizeof(SFTP_PACKET)); + u32 size; + packet->sftp=sftp; + packet->payload=buffer_new(); + if(channel_read(sftp->channel,packet->payload,4,0)<=0){ + buffer_free(packet->payload); + free(packet); + return NULL; + } + buffer_get_u32(packet->payload,&size); + size=ntohl(size); + if(channel_read(sftp->channel,packet->payload,1,0)<=0){ + buffer_free(packet->payload); + free(packet); + return NULL; + } + buffer_get_u8(packet->payload,&packet->type); + if(size>1) + if(channel_read(sftp->channel,packet->payload,size-1,0)<=0){ + buffer_free(packet->payload); + free(packet); + return NULL; + } + return packet; +} + +static SFTP_MESSAGE *sftp_message_new(){ + SFTP_MESSAGE *msg=malloc(sizeof(SFTP_MESSAGE)); + memset(msg,0,sizeof(*msg)); + msg->payload=buffer_new(); + return msg; +} + +static void sftp_message_free(SFTP_MESSAGE *msg){ + if(msg->payload) + buffer_free(msg->payload); + free(msg); +} + +SFTP_MESSAGE *sftp_get_message(SFTP_PACKET *packet){ + SFTP_MESSAGE *msg=sftp_message_new(); + msg->sftp=packet->sftp; + msg->packet_type=packet->type; + if((packet->type!=SSH_FXP_STATUS)&&(packet->type!=SSH_FXP_HANDLE) && + (packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS) + && (packet->type != SSH_FXP_NAME)){ + ssh_set_error(packet->sftp->session,SSH_FATAL,"get_message : unknown packet type %d\n",packet->type); + sftp_message_free(msg); + return NULL; + } + if(buffer_get_u32(packet->payload,&msg->id)!=sizeof(u32)){ + ssh_set_error(packet->sftp->session,SSH_FATAL,"invalid packet %d : no ID",packet->type); + sftp_message_free(msg); + return NULL; + } + ssh_say(2,"packet with id %d type %d\n",msg->id,msg->packet_type); + buffer_add_data(msg->payload,buffer_get_rest(packet->payload),buffer_get_rest_len(packet->payload)); + return msg; +} + +int sftp_read_and_dispatch(SFTP_SESSION *session){ + SFTP_PACKET *packet; + SFTP_MESSAGE *message=NULL; + packet=sftp_packet_read(session); + if(!packet) + return -1; /* something nasty happened reading the packet */ + message=sftp_get_message(packet); + sftp_packet_free(packet); + if(!message) + return -1; + sftp_enqueue(session,message); + return 0; +} + +static void sftp_packet_free(SFTP_PACKET *packet){ + if(packet->payload) + buffer_free(packet->payload); + free(packet); +} + +int sftp_init(SFTP_SESSION *sftp){ + SFTP_PACKET *packet; + BUFFER *buffer=buffer_new(); + STRING *ext_name_s=NULL, *ext_data_s=NULL; + char *ext_name,*ext_data; + u32 version=htonl(LIBSFTP_VERSION); + buffer_add_u32(buffer,version); + sftp_packet_write(sftp,SSH_FXP_INIT,buffer); + buffer_free(buffer); + packet=sftp_packet_read(sftp); + if(!packet) + return -1; + if(packet->type != SSH_FXP_VERSION){ + ssh_set_error(sftp->session,SSH_FATAL,"Received a %d messages instead of SSH_FXP_VERSION",packet->type); + sftp_packet_free(packet); + return -1; + } + buffer_get_u32(packet->payload,&version); + version=ntohl(version); + if(!(ext_name_s=buffer_get_ssh_string(packet->payload))||!(ext_data_s=buffer_get_ssh_string(packet->payload))) + ssh_say(2,"sftp server version %d\n",version); + else{ + ext_name=string_to_char(ext_name_s); + ext_data=string_to_char(ext_data_s); + ssh_say(2,"sftp server version %d (%s,%s)\n",version,ext_name,ext_data); + free(ext_name); + free(ext_data); + } + if(ext_name_s) + free(ext_name_s); + if(ext_data_s) + free(ext_data_s); + sftp_packet_free(packet); + sftp->server_version=version; + return 0; +} + +REQUEST_QUEUE *request_queue_new(SFTP_MESSAGE *msg){ + REQUEST_QUEUE *queue=malloc(sizeof(REQUEST_QUEUE)); + memset(queue,0,sizeof(REQUEST_QUEUE)); + queue->message=msg; + return queue; +} + +void request_queue_free(REQUEST_QUEUE *queue){ + memset(queue,0,sizeof(*queue)); + free(queue); +} + +void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg){ + REQUEST_QUEUE *queue=request_queue_new(msg); + REQUEST_QUEUE *ptr; + ssh_say(2,"queued msg type %d id %d\n",msg->id,msg->packet_type); + if(!session->queue) + session->queue=queue; + else { + ptr=session->queue; + while(ptr->next){ + ptr=ptr->next; /* find end of linked list */ + } + ptr->next=queue; /* add it on bottom */ + } +} + +/* pulls of a message from the queue based on the ID. returns null if no message has been found */ +SFTP_MESSAGE *sftp_dequeue(SFTP_SESSION *session, u32 id){ + REQUEST_QUEUE *queue,*prev=NULL; + SFTP_MESSAGE *msg; + if(session->queue==NULL){ + return NULL; + } + queue=session->queue; + while(queue){ + if(queue->message->id==id){ + /* remove from queue */ + if(prev==NULL){ + session->queue=queue->next; + } else { + prev->next=queue->next; + } + msg=queue->message; + request_queue_free(queue); + ssh_say(2,"dequeued msg id %d type %d\n",msg->id,msg->packet_type); + return msg; + } + prev=queue; + queue=queue->next; + } + return NULL; +} + +/* assigns a new sftp ID for new requests and assures there is no collision between them. */ +u32 sftp_get_new_id(SFTP_SESSION *session){ + return ++session->id_counter; +} + +STATUS_MESSAGE *parse_status_msg(SFTP_MESSAGE *msg){ + STATUS_MESSAGE *status; + if(msg->packet_type != SSH_FXP_STATUS){ + ssh_set_error(msg->sftp->session, SSH_FATAL,"Not a ssh_fxp_status message passed in !"); + return NULL; + } + status=malloc(sizeof(STATUS_MESSAGE)); + memset(status,0,sizeof(*status)); + status->id=msg->id; + if( (buffer_get_u32(msg->payload,&status->status)!= 4) + || !(status->error=buffer_get_ssh_string(msg->payload)) || + !(status->lang=buffer_get_ssh_string(msg->payload))){ + if(status->error) + free(status->error); + /* status->lang never get allocated if something failed */ + free(status); + ssh_set_error(msg->sftp->session,SSH_FATAL,"invalid SSH_FXP_STATUS message"); + return NULL; + } + status->status=ntohl(status->status); + status->errormsg=string_to_char(status->error); + status->langmsg=string_to_char(status->lang); + return status; +} + +void status_msg_free(STATUS_MESSAGE *status){ + if(status->errormsg) + free(status->errormsg); + if(status->error) + free(status->error); + if(status->langmsg) + free(status->langmsg); + if(status->lang) + free(status->lang); + free(status); +} + +SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){ + SFTP_FILE *file; + if(msg->packet_type != SSH_FXP_HANDLE){ + ssh_set_error(msg->sftp->session,SSH_FATAL,"Not a ssh_fxp_handle message passed in !"); + return NULL; + } + file=malloc(sizeof(SFTP_FILE)); + memset(file,0,sizeof(*file)); + file->sftp=msg->sftp; + file->handle=buffer_get_ssh_string(msg->payload); + file->offset=0; + file->eof=0; + if(!file->handle){ + ssh_set_error(msg->sftp->session,SSH_FATAL,"Invalid SSH_FXP_HANDLE message"); + free(file); + return NULL; + } + return file; +} + +SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, char *path){ + SFTP_DIR *dir=NULL; + SFTP_FILE *file; + STATUS_MESSAGE *status; + SFTP_MESSAGE *msg=NULL; + STRING *path_s; + BUFFER *payload=buffer_new(); + u32 id=sftp_get_new_id(sftp); + buffer_add_u32(payload,id); + path_s=string_from_char(path); + buffer_add_ssh_string(payload,path_s); + free(path_s); + sftp_packet_write(sftp,SSH_FXP_OPENDIR,payload); + buffer_free(payload); + while(!msg){ + if(sftp_read_and_dispatch(sftp)) + /* something nasty has happened */ + return NULL; + msg=sftp_dequeue(sftp,id); + } + switch (msg->packet_type){ + case SSH_FXP_STATUS: + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return NULL; + ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); + status_msg_free(status); + return NULL; + case SSH_FXP_HANDLE: + file=parse_handle_msg(msg); + sftp_message_free(msg); + if(file){ + dir=malloc(sizeof(SFTP_DIR)); + memset(dir,0,sizeof(*dir)); + dir->sftp=sftp; + dir->name=strdup(path); + dir->handle=file->handle; + free(file); + } + return dir; + default: + ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during opendir!",msg->packet_type); + sftp_message_free(msg); + } + return NULL; +} + +/* parse the attributes from a payload from some messages */ +/* i coded it on baselines from the protocol version 4. */ +/* please excuse me for the inaccuracy of the code. it isn't my fault, it's sftp draft's one */ +/* this code is dead anyway ... */ +/* version 4 specific code */ +SFTP_ATTRIBUTES *sftp_parse_attr_4(SFTP_SESSION *sftp,BUFFER *buf,int expectnames){ + u32 flags=0; + SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES)); + STRING *owner=NULL; + STRING *group=NULL; + int ok=0; + memset(attr,0,sizeof(*attr)); + /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */ + do { + if(buffer_get_u32(buf,&flags)!=4) + break; + flags=ntohl(flags); + attr->flags=flags; + if(flags & SSH_FILEXFER_ATTR_SIZE){ + if(buffer_get_u64(buf,&attr->size)!=8) + break; + attr->size=ntohll(attr->size); + } + if(flags & SSH_FILEXFER_ATTR_OWNERGROUP){ + if(!(owner=buffer_get_ssh_string(buf))) + break; + if(!(group=buffer_get_ssh_string(buf))) + break; + } + if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){ + if(buffer_get_u32(buf,&attr->permissions)!=4) + break; + attr->permissions=ntohl(attr->permissions); + } + if(flags & SSH_FILEXFER_ATTR_ACCESSTIME){ + if(buffer_get_u64(buf,&attr->atime64)!=8) + break; + attr->atime64=ntohll(attr->atime64); + } + if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){ + if(buffer_get_u32(buf,&attr->atime_nseconds)!=4) + break; + attr->atime_nseconds=ntohl(attr->atime_nseconds); + } + if(flags & SSH_FILEXFER_ATTR_CREATETIME){ + if(buffer_get_u64(buf,&attr->createtime)!=8) + break; + attr->createtime=ntohll(attr->createtime); + } + if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){ + if(buffer_get_u32(buf,&attr->createtime_nseconds)!=4) + break; + attr->createtime_nseconds=ntohl(attr->createtime_nseconds); + } + if(flags & SSH_FILEXFER_ATTR_MODIFYTIME){ + if(buffer_get_u64(buf,&attr->mtime64)!=8) + break; + attr->mtime64=ntohll(attr->mtime64); + } + if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){ + if(buffer_get_u32(buf,&attr->mtime_nseconds)!=4) + break; + attr->mtime_nseconds=ntohl(attr->mtime_nseconds); + } + if(flags & SSH_FILEXFER_ATTR_ACL){ + if(!(attr->acl=buffer_get_ssh_string(buf))) + break; + } + if (flags & SSH_FILEXFER_ATTR_EXTENDED){ + if(buffer_get_u32(buf,&attr->extended_count)!=4) + break; + attr->extended_count=ntohl(attr->extended_count); + while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf)) + && (attr->extended_data=buffer_get_ssh_string(buf))){ + attr->extended_count--; + } + if(attr->extended_count) + break; + } + ok=1; + } while (0); + if(!ok){ + /* break issued somewhere */ + if(owner) + free(owner); + if(group) + free(group); + if(attr->acl) + free(attr->acl); + if(attr->extended_type) + free(attr->extended_type); + if(attr->extended_data) + free(attr->extended_data); + free(attr); + ssh_set_error(sftp->session,SSH_FATAL,"Invalid ATTR structure"); + return NULL; + } + /* everything went smoothly */ + if(owner){ + attr->owner=string_to_char(owner); + free(owner); + } + if(group){ + attr->group=string_to_char(group); + free(group); + } + return attr; +} + +/* Version 3 code. it is the only one really supported (the draft for the 4 misses clarifications) */ +/* maybe a paste of the draft is better than the code */ +/* + uint32 flags + uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE + uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS + uint32 atime present only if flag SSH_FILEXFER_ACMODTIME + uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME + uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count */ +SFTP_ATTRIBUTES *sftp_parse_attr_3(SFTP_SESSION *sftp,BUFFER *buf,int expectname){ + u32 flags=0; + STRING *name; + STRING *longname; + SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES)); + int ok=0; + memset(attr,0,sizeof(*attr)); + /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */ + do { + if(expectname){ + if(!(name=buffer_get_ssh_string(buf))) + break; + attr->name=string_to_char(name); + free(name); + ssh_say(2,"name : %s\n",attr->name); + if(!(longname=buffer_get_ssh_string(buf))) + break; + attr->longname=string_to_char(longname); + free(longname); + } + if(buffer_get_u32(buf,&flags)!=sizeof(u32)) + break; + flags=ntohl(flags); + attr->flags=flags; + ssh_say(2,"flags : %.8lx\n",flags); + if(flags & SSH_FILEXFER_ATTR_SIZE){ + if(buffer_get_u64(buf,&attr->size)!=sizeof(u64)) + break; + attr->size=ntohll(attr->size); + ssh_say(2,"size : %lld\n",attr->size); + } + if(flags & SSH_FILEXFER_ATTR_UIDGID){ + if(buffer_get_u32(buf,&attr->uid)!=sizeof(u32)) + break; + if(buffer_get_u32(buf,&attr->gid)!=sizeof(u32)) + break; + attr->uid=ntohl(attr->uid); + attr->gid=ntohl(attr->gid); + } + if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){ + if(buffer_get_u32(buf,&attr->permissions)!=sizeof(u32)) + break; + attr->permissions=ntohl(attr->permissions); + } + if(flags & SSH_FILEXFER_ATTR_ACMODTIME){ + if(buffer_get_u32(buf,&attr->atime)!=sizeof(u32)) + break; + attr->atime=ntohl(attr->atime); + if(buffer_get_u32(buf,&attr->mtime)!=sizeof(u32)) + break; + attr->mtime=ntohl(attr->mtime); + } + if (flags & SSH_FILEXFER_ATTR_EXTENDED){ + if(buffer_get_u32(buf,&attr->extended_count)!=sizeof(u32)) + break; + attr->extended_count=ntohl(attr->extended_count); + while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf)) + && (attr->extended_data=buffer_get_ssh_string(buf))){ + attr->extended_count--; + } + if(attr->extended_count) + break; + } + ok=1; + } while (0); + if(!ok){ + /* break issued somewhere */ + if(attr->name) + free(attr->name); + if(attr->extended_type) + free(attr->extended_type); + if(attr->extended_data) + free(attr->extended_data); + free(attr); + ssh_set_error(sftp->session,SSH_FATAL,"Invalid ATTR structure"); + return NULL; + } + /* everything went smoothly */ + return attr; +} + +void buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr){ + u32 flags=(attr?attr->flags:0); + flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME); + buffer_add_u32(buffer,htonl(flags)); + if(attr){ + if (flags & SSH_FILEXFER_ATTR_SIZE) + { + buffer_add_u64(buffer, htonll(attr->size)); + } + if(flags & SSH_FILEXFER_ATTR_UIDGID){ + buffer_add_u32(buffer,htonl(attr->uid)); + buffer_add_u32(buffer,htonl(attr->gid)); + } + if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){ + buffer_add_u32(buffer,htonl(attr->permissions)); + } + if (flags & SSH_FILEXFER_ATTR_ACMODTIME) + { + buffer_add_u32(buffer, htonl(attr->atime)); + buffer_add_u32(buffer, htonl(attr->mtime)); + } + } +} + + +SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname){ + switch(session->server_version){ + case 4: + return sftp_parse_attr_4(session,buf,expectname); + case 3: + return sftp_parse_attr_3(session,buf,expectname); + default: + ssh_set_error(session->session,SSH_FATAL,"Version %d unsupported by client",session->server_version); + return NULL; + } + return NULL; +} + +int sftp_server_version(SFTP_SESSION *sftp){ + return sftp->server_version; +} + +SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *sftp, SFTP_DIR *dir){ + BUFFER *payload; + u32 id; + SFTP_MESSAGE *msg=NULL; + STATUS_MESSAGE *status; + SFTP_ATTRIBUTES *attr; + if(!dir->buffer){ + payload=buffer_new(); + id=sftp_get_new_id(sftp); + buffer_add_u32(payload,id); + buffer_add_ssh_string(payload,dir->handle); + sftp_packet_write(sftp,SSH_FXP_READDIR,payload); + buffer_free(payload); + ssh_say(2,"sent a ssh_fxp_readdir with id %d\n",id); + while(!msg){ + if(sftp_read_and_dispatch(sftp)) + /* something nasty has happened */ + return NULL; + msg=sftp_dequeue(sftp,id); + } + switch (msg->packet_type){ + case SSH_FXP_STATUS: + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return NULL; + if(status->status==SSH_FX_EOF){ + dir->eof=1; + status_msg_free(status); + return NULL; + } + ssh_set_error(sftp->session,SSH_FATAL,"Unknown error status : %d",status->status); + status_msg_free(status); + return NULL; + case SSH_FXP_NAME: + buffer_get_u32(msg->payload,&dir->count); + dir->count=ntohl(dir->count); + dir->buffer=msg->payload; + msg->payload=NULL; + sftp_message_free(msg); + break; + default: + ssh_set_error(sftp->session,SSH_FATAL,"unsupported message back %d",msg->packet_type); + sftp_message_free(msg); + return NULL; + } + } + /* now dir->buffer contains a buffer and dir->count != 0 */ + if(dir->count==0){ + ssh_set_error(sftp->session,SSH_FATAL,"Count of files sent by the server is zero, which is invalid, or libsftp bug"); + return NULL; + } + ssh_say(2,"Count is %d\n",dir->count); + attr=sftp_parse_attr(sftp,dir->buffer,1); + dir->count--; + if(dir->count==0){ + buffer_free(dir->buffer); + dir->buffer=NULL; + } + return attr; +} + +int sftp_dir_eof(SFTP_DIR *dir){ + return (dir->eof); +} + +void sftp_attributes_free(SFTP_ATTRIBUTES *file){ + if(file->name) + free(file->name); + if(file->longname) + free(file->longname); + if(file->acl) + free(file->acl); + if(file->extended_data) + free(file->extended_data); + if(file->extended_type) + free(file->extended_type); + if(file->group) + free(file->group); + if(file->owner) + free(file->owner); + free(file); +} + +static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){ + SFTP_MESSAGE *msg=NULL; + STATUS_MESSAGE *status; + int id=sftp_get_new_id(sftp); + int err=0; + BUFFER *buffer=buffer_new(); + buffer_add_u32(buffer,id); + buffer_add_ssh_string(buffer,handle); + sftp_packet_write(sftp,SSH_FXP_CLOSE,buffer); + buffer_free(buffer); + while(!msg){ + if(sftp_read_and_dispatch(sftp)) + /* something nasty has happened */ + return -1; + msg=sftp_dequeue(sftp,id); + } + switch (msg->packet_type){ + case SSH_FXP_STATUS: + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return -1; + if(status->status != SSH_FX_OK){ + ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); + err=-1; + } + status_msg_free(status); + return err; + default: + ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during sftp_handle_close!",msg->packet_type); + sftp_message_free(msg); + } + return -1; +} + +int sftp_file_close(SFTP_FILE *file){ + int err=0; + if(file->name) + free(file->name); + if(file->handle){ + err=sftp_handle_close(file->sftp,file->handle); + free(file->handle); + } + free(file); + return err; +} + +int sftp_dir_close(SFTP_DIR *dir){ + int err=0; + if(dir->name) + free(dir->name); + if(dir->handle){ + err=sftp_handle_close(dir->sftp,dir->handle); + free(dir->handle); + } + if(dir->buffer) + buffer_free(dir->buffer); + free(dir); + return err; +} + +SFTP_FILE *sftp_open(SFTP_SESSION *sftp, char *file, int access, SFTP_ATTRIBUTES *attr){ + SFTP_FILE *handle; + SFTP_MESSAGE *msg=NULL; + STATUS_MESSAGE *status; + u32 flags=0; + u32 id=sftp_get_new_id(sftp); + BUFFER *buffer=buffer_new(); + STRING *filename; + if(access & O_RDONLY) + flags|=SSH_FXF_READ; + if(access & O_WRONLY) + flags |= SSH_FXF_WRITE; + if(access & O_RDWR) + flags|=(SSH_FXF_WRITE | SSH_FXF_READ); + if(access & O_CREAT) + flags |=SSH_FXF_CREAT; + if(access & O_TRUNC) + flags |=SSH_FXF_TRUNC; + if(access & O_EXCL) + flags |= SSH_FXF_EXCL; + buffer_add_u32(buffer,id); + filename=string_from_char(file); + buffer_add_ssh_string(buffer,filename); + free(filename); + buffer_add_u32(buffer,htonl(flags)); + buffer_add_attributes(buffer,attr); + sftp_packet_write(sftp,SSH_FXP_OPEN,buffer); + buffer_free(buffer); + while(!msg){ + if(sftp_read_and_dispatch(sftp)) + /* something nasty has happened */ + return NULL; + msg=sftp_dequeue(sftp,id); + } + switch (msg->packet_type){ + case SSH_FXP_STATUS: + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return NULL; + ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); + status_msg_free(status); + return NULL; + case SSH_FXP_HANDLE: + handle=parse_handle_msg(msg); + sftp_message_free(msg); + return handle; + default: + ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during open!",msg->packet_type); + sftp_message_free(msg); + } + return NULL; +} + +void sftp_file_set_nonblocking(SFTP_FILE *handle){ + handle->nonblocking=1; +} +void sftp_file_set_blocking(SFTP_FILE *handle){ + handle->nonblocking=0; +} + +int sftp_read(SFTP_FILE *handle, void *data, int len){ + SFTP_MESSAGE *msg=NULL; + STATUS_MESSAGE *status; + SFTP_SESSION *sftp=handle->sftp; + STRING *datastring; + int id; + int err=0; + BUFFER *buffer; + if(handle->eof) + return 0; + buffer=buffer_new(); + id=sftp_get_new_id(handle->sftp); + buffer_add_u32(buffer,id); + buffer_add_ssh_string(buffer,handle->handle); + buffer_add_u64(buffer,htonll(handle->offset)); + buffer_add_u32(buffer,htonl(len)); + sftp_packet_write(handle->sftp,SSH_FXP_READ,buffer); + buffer_free(buffer); + while(!msg){ + if (handle->nonblocking){ + if(channel_poll(handle->sftp->channel,0)==0){ + /* we cannot block */ + return 0; + } + } + if(sftp_read_and_dispatch(handle->sftp)) + /* something nasty has happened */ + return -1; + msg=sftp_dequeue(handle->sftp,id); + } + switch (msg->packet_type){ + case SSH_FXP_STATUS: + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return -1; + if(status->status != SSH_FX_EOF){ + ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); + err=-1; + } + else + handle->eof=1; + status_msg_free(status); + return err?err:0; + case SSH_FXP_DATA: + datastring=buffer_get_ssh_string(msg->payload); + sftp_message_free(msg); + if(!datastring){ + ssh_set_error(sftp->session,SSH_FATAL,"Received invalid DATA packet from sftp server"); + return -1; + } + if(string_len(datastring)>len){ + ssh_set_error(sftp->session,SSH_FATAL,"Received a too big DATA packet from sftp server : %d and asked for %d", + string_len(datastring),len); + free(datastring); + return -1; + } + len=string_len(datastring); + handle->offset+=len; + memcpy(data,datastring->string,len); + free(datastring); + return len; + default: + ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type); + sftp_message_free(msg); + return -1; + } + return -1; /* not reached */ +} + +int sftp_write(SFTP_FILE *file, void *data, int len){ + SFTP_MESSAGE *msg=NULL; + STATUS_MESSAGE *status; + STRING *datastring; + SFTP_SESSION *sftp=file->sftp; + int id; + int err=0; + BUFFER *buffer; + buffer=buffer_new(); + id=sftp_get_new_id(file->sftp); + buffer_add_u32(buffer,id); + buffer_add_ssh_string(buffer,file->handle); + buffer_add_u64(buffer,htonll(file->offset)); + datastring=string_new(len); + string_fill(datastring,data,len); + buffer_add_ssh_string(buffer,datastring); + free(datastring); + if(sftp_packet_write(file->sftp,SSH_FXP_WRITE,buffer) != buffer_get_len(buffer)){ + ssh_say(1,"sftp_packet_write did not write as much data as expected\n"); + } + buffer_free(buffer); + while(!msg){ + if(sftp_read_and_dispatch(file->sftp)) + /* something nasty has happened */ + return -1; + msg=sftp_dequeue(file->sftp,id); + } + switch (msg->packet_type){ + case SSH_FXP_STATUS: + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return -1; + if(status->status != SSH_FX_OK){ + ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); + err=-1; + } + file->offset+=len; + status_msg_free(status); + return (err?err:len); + default: + ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during write!",msg->packet_type); + sftp_message_free(msg); + return -1; + } + return -1; /* not reached */ +} + +void sftp_seek(SFTP_FILE *file, int new_offset){ + file->offset=new_offset; +} + +unsigned long sftp_tell(SFTP_FILE *file){ + return file->offset; +} + +void sftp_rewind(SFTP_FILE *file){ + file->offset=0; +} + +/* code written by Nick */ +int sftp_rm(SFTP_SESSION *sftp, char *file) { + u32 id = sftp_get_new_id(sftp); + BUFFER *buffer = buffer_new(); + STRING *filename = string_from_char(file); + SFTP_MESSAGE *msg = NULL; + STATUS_MESSAGE *status = NULL; + + buffer_add_u32(buffer, id); + buffer_add_ssh_string(buffer, filename); + free(filename); + sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer); + buffer_free(buffer); + while (!msg) { + if (sftp_read_and_dispatch(sftp)) { + return -1; + } + msg = sftp_dequeue(sftp, id); + } + if (msg->packet_type == SSH_FXP_STATUS) { + /* by specification, this command's only supposed to return SSH_FXP_STATUS */ + status = parse_status_msg(msg); + sftp_message_free(msg); + if (!status) + return -1; + if (status->status != SSH_FX_OK) { + /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ + ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); + status_msg_free(status); + return -1; + } + status_msg_free(status); + return 0; /* at this point, everything turned out OK */ + } else { + ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to remove file", msg->packet_type); + sftp_message_free(msg); + } + return -1; +} + +/* code written by Nick */ +int sftp_rmdir(SFTP_SESSION *sftp, char *directory) { + u32 id = sftp_get_new_id(sftp); + BUFFER *buffer = buffer_new(); + STRING *filename = string_from_char(directory); + SFTP_MESSAGE *msg = NULL; + STATUS_MESSAGE *status = NULL; + + buffer_add_u32(buffer, id); + buffer_add_ssh_string(buffer, filename); + free(filename); + sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer); + buffer_free(buffer); + while (!msg) { + if (sftp_read_and_dispatch(sftp)) + { + return -1; + } + msg = sftp_dequeue(sftp, id); + } + if (msg->packet_type == SSH_FXP_STATUS) /* by specification, this command's only supposed to return SSH_FXP_STATUS */ + { + status = parse_status_msg(msg); + sftp_message_free(msg); + if (!status) + { + return -1; + } + else if (status->status != SSH_FX_OK) /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ + { + ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); + status_msg_free(status); + return -1; + } + status_msg_free(status); + return 0; /* at this point, everything turned out OK */ + } + else + { + ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to remove directory", msg->packet_type); + sftp_message_free(msg); + } + return -1; +} + +/* Code written by Nick */ +int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) { + u32 id = sftp_get_new_id(sftp); + BUFFER *buffer = buffer_new(); + STRING *path = string_from_char(directory); + SFTP_MESSAGE *msg = NULL; + STATUS_MESSAGE *status = NULL; + + buffer_add_u32(buffer, id); + buffer_add_ssh_string(buffer, path); + free(path); + buffer_add_attributes(buffer, attr); + sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer); + buffer_free(buffer); + while (!msg) { + if (sftp_read_and_dispatch(sftp)) + return -1; + msg = sftp_dequeue(sftp, id); + } + if (msg->packet_type == SSH_FXP_STATUS) { + /* by specification, this command's only supposed to return SSH_FXP_STATUS */ + status = parse_status_msg(msg); + sftp_message_free(msg); + if (!status) + return -1; + else + if (status->status != SSH_FX_OK) { + /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ + ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); + status_msg_free(status); + return -1; + } + status_msg_free(status); + return 0; /* at this point, everything turned out OK */ + } else { + ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to make directory", msg->packet_type); + sftp_message_free(msg); + } + return -1; +} + +/* code written by nick */ +int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) { + u32 id = sftp_get_new_id(sftp); + BUFFER *buffer = buffer_new(); + STRING *oldpath = string_from_char(original); + STRING *newpath = string_from_char(newname); + SFTP_MESSAGE *msg = NULL; + STATUS_MESSAGE *status = NULL; + + buffer_add_u32(buffer, id); + buffer_add_ssh_string(buffer, oldpath); + free(oldpath); + buffer_add_ssh_string(buffer, newpath); + free(newpath); + sftp_packet_write(sftp, SSH_FXP_RENAME, buffer); + buffer_free(buffer); + while (!msg) { + if (sftp_read_and_dispatch(sftp)) + return -1; + msg = sftp_dequeue(sftp, id); + } + if (msg->packet_type == SSH_FXP_STATUS) { + /* by specification, this command's only supposed to return SSH_FXP_STATUS */ + status = parse_status_msg(msg); + sftp_message_free(msg); + if (!status) + return -1; + else if (status->status != SSH_FX_OK) { + /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ + ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); + status_msg_free(status); + return -1; + } + status_msg_free(status); + return 0; /* at this point, everything turned out OK */ + } else { + ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to rename", msg->packet_type); + sftp_message_free(msg); + } + return -1; +} + +/* Code written by Nick */ +int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) { + u32 id = sftp_get_new_id(sftp); + BUFFER *buffer = buffer_new(); + STRING *path = string_from_char(file); + SFTP_MESSAGE *msg = NULL; + STATUS_MESSAGE *status = NULL; + + buffer_add_u32(buffer, id); + buffer_add_ssh_string(buffer, path); + free(path); + buffer_add_attributes(buffer, attr); + sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer); + buffer_free(buffer); + while (!msg) { + if (sftp_read_and_dispatch(sftp)) + return -1; + msg = sftp_dequeue(sftp, id); + } + if (msg->packet_type == SSH_FXP_STATUS) { + /* by specification, this command's only supposed to return SSH_FXP_STATUS */ + status = parse_status_msg(msg); + sftp_message_free(msg); + if (!status) + return -1; + else if (status->status != SSH_FX_OK) { + /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */ + ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); + status_msg_free(status); + return -1; + } + status_msg_free(status); + return 0; /* at this point, everything turned out OK */ + } else { + ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to set stats", msg->packet_type); + sftp_message_free(msg); + } + return -1; +} + +/* another code written by Nick */ +char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path) +{ + u32 id = sftp_get_new_id(sftp); + BUFFER *buffer = buffer_new(); + STRING *pathstr = string_from_char(path); + STRING *name = NULL; + SFTP_MESSAGE *msg = NULL; + STATUS_MESSAGE *status = NULL; + char *cname; + u32 ignored; + + buffer_add_u32(buffer, id); + buffer_add_ssh_string(buffer, pathstr); + free(pathstr); + sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer); + buffer_free(buffer); + while (!msg) + { + if (sftp_read_and_dispatch(sftp)) + return NULL; + msg = sftp_dequeue(sftp, id); + } + if (msg->packet_type == SSH_FXP_NAME) /* good response */ + { + buffer_get_u32(msg->payload, &ignored); /* we don't care about "count" */ + name = buffer_get_ssh_string(msg->payload); /* we only care about the file name string */ + cname = string_to_char(name); + free(name); + return cname; + } + else if (msg->packet_type == SSH_FXP_STATUS) /* bad response (error) */ + { + status = parse_status_msg(msg); + sftp_message_free(msg); + if (!status) + return NULL; + ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg); + status_msg_free(status); + } + else /* this shouldn't happen */ + { + ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to set stats", msg->packet_type); + sftp_message_free(msg); + } + return NULL; +} + +SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){ + u32 id=sftp_get_new_id(sftp); + BUFFER *buffer=buffer_new(); + STRING *pathstr= string_from_char(path); + SFTP_MESSAGE *msg=NULL; + STATUS_MESSAGE *status=NULL; + SFTP_ATTRIBUTES *pattr=NULL; + + buffer_add_u32(buffer,id); + buffer_add_ssh_string(buffer,pathstr); + free(pathstr); + sftp_packet_write(sftp,param,buffer); + buffer_free(buffer); + while(!msg){ + if(sftp_read_and_dispatch(sftp)) + return NULL; + msg=sftp_dequeue(sftp,id); + } + if(msg->packet_type==SSH_FXP_ATTRS){ + pattr=sftp_parse_attr(sftp,msg->payload,0); + return pattr; + } + if(msg->packet_type== SSH_FXP_STATUS){ + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return NULL; + ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg); + status_msg_free(status); + return NULL; + } + ssh_set_error(sftp->session,SSH_FATAL,"Received mesg %d during stat(),mesg->packet_type"); + sftp_message_free(msg); + return NULL; +} + +SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path){ + return sftp_xstat(session,path,SSH_FXP_STAT); +} +SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path){ + return sftp_xstat(session,path,SSH_FXP_LSTAT); +} + +SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file) { + u32 id=sftp_get_new_id(file->sftp); + BUFFER *buffer=buffer_new(); + SFTP_MESSAGE *msg=NULL; + STATUS_MESSAGE *status=NULL; + SFTP_ATTRIBUTES *pattr=NULL; + + buffer_add_u32(buffer,id); + buffer_add_ssh_string(buffer,file->handle); + sftp_packet_write(file->sftp,SSH_FXP_FSTAT,buffer); + buffer_free(buffer); + while(!msg){ + if(sftp_read_and_dispatch(file->sftp)) + return NULL; + msg=sftp_dequeue(file->sftp,id); + } + if(msg->packet_type==SSH_FXP_ATTRS){ + pattr=sftp_parse_attr(file->sftp,msg->payload,0); + return pattr; + } + if(msg->packet_type== SSH_FXP_STATUS){ + status=parse_status_msg(msg); + sftp_message_free(msg); + if(!status) + return NULL; + ssh_set_error(file->sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg); + status_msg_free(status); + return NULL; + } + ssh_set_error(file->sftp->session,SSH_FATAL,"Received mesg %d during fstat(),mesg->packet_type"); + sftp_message_free(msg); + return NULL; +} + + +#endif /* NO_SFTP */ diff --git a/libssh/string.c b/libssh/string.c new file mode 100644 index 00000000..1ae5bd2d --- /dev/null +++ b/libssh/string.c @@ -0,0 +1,70 @@ +/*string.c */ +/* string manipulations... */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include "libssh/priv.h" + +STRING *string_new(u32 size){ + STRING *str=malloc(size + 4); + str->size=htonl(size); + return str; +} + +void string_fill(STRING *str,void *data,int len){ + memcpy(str->string,data,len); +} + +STRING *string_from_char(char *what){ + STRING *ptr; + int len=strlen(what); + ptr=malloc(4 + len); + ptr->size=htonl(len); + memcpy(ptr->string,what,len); + return ptr; +} + +int string_len(STRING *str){ + return ntohl(str->size); +} + +char *string_to_char(STRING *str){ + int len=ntohl(str->size)+1; + char *string=malloc(len); + memcpy(string,str->string,len-1); + string[len-1]=0; + return string; +} + +STRING *string_copy(STRING *str){ + STRING *ret=malloc(ntohl(str->size)+4); + ret->size=str->size; + memcpy(ret->string,str->string,ntohl(str->size)); + return ret; +} + +void string_burn(STRING *s){ + memset(s->string,'X',string_len(s)); +} + diff --git a/libssh/wrapper.c b/libssh/wrapper.c new file mode 100644 index 00000000..1c49ed79 --- /dev/null +++ b/libssh/wrapper.c @@ -0,0 +1,329 @@ +/* wrapper.c */ +/* wrapping functions for crypto functions. */ +/* why a wrapper ? let's say you want to port libssh from libcrypto of openssl to libfoo */ +/* you are going to spend hours to remove every references to SHA1_Update() to libfoo_sha1_update */ +/* after the work is finished, you're going to have only this file to modify */ +/* it's not needed to say that your modifications are welcome */ + +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "libssh/priv.h" +#include "libssh/crypto.h" +#include +#ifdef OPENSSL_CRYPTO +#include +#include +#include +#include +#include +#include +#ifdef HAVE_OPENSSL_AES_H +#define HAS_AES +#include +#endif +#ifdef HAVE_OPENSSL_BLOWFISH_H +#define HAS_BLOWFISH +#include +#endif + +#include + +#if (OPENSSL_VERSION_NUMBER<0x009070000) +#define OLD_CRYPTO +#endif + +SHACTX *sha1_init(){ + SHACTX *c=malloc(sizeof(SHACTX)); + SHA1_Init(c); + return c; +} +void sha1_update(SHACTX *c, const void *data, unsigned long len){ + SHA1_Update(c,data,len); +} +void sha1_final(unsigned char *md,SHACTX *c){ + SHA1_Final(md,c); + free(c); +} +void sha1(unsigned char *digest,int len,unsigned char *hash){ + SHA1(digest,len,hash); +} + +MD5CTX *md5_init(){ + MD5CTX *c=malloc(sizeof(MD5CTX)); + MD5_Init(c); + return c; +} +void md5_update(MD5CTX *c, const void *data, unsigned long len){ + MD5_Update(c,data,len); +} +void md5_final(unsigned char *md,MD5CTX *c){ + MD5_Final(md,c); + free(c); +} + +HMACCTX *hmac_init(const void *key, int len,int type){ + HMAC_CTX *ctx; + ctx=malloc(sizeof(HMAC_CTX)); +#ifndef OLD_CRYPTO + HMAC_CTX_init(ctx); // openssl 0.9.7 requires it. +#endif + switch(type){ + case HMAC_SHA1: + HMAC_Init(ctx,key,len,EVP_sha1()); + break; + case HMAC_MD5: + HMAC_Init(ctx,key,len,EVP_md5()); + break; + default: + free(ctx); + ctx=NULL; + } + return ctx; +} +void hmac_update(HMACCTX *ctx,const void *data, unsigned long len){ + HMAC_Update(ctx,data,len); +} +void hmac_final(HMACCTX *ctx,unsigned char *hashmacbuf,int *len){ + HMAC_Final(ctx,hashmacbuf,len); +#ifndef OLD_CRYPTO + HMAC_CTX_cleanup(ctx); +#else + HMAC_cleanup(ctx); +#endif + free(ctx); +} + +static void alloc_key(struct crypto_struct *cipher){ + cipher->key=malloc(cipher->keylen); +} + +#ifdef HAS_BLOWFISH +/* the wrapper functions for blowfish */ +static void blowfish_set_key(struct crypto_struct *cipher, void *key){ + if(!cipher->key){ + alloc_key(cipher); + BF_set_key(cipher->key,16,key); + } +} + +static void blowfish_encrypt(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV){ + BF_cbc_encrypt(in,out,len,cipher->key,IV,BF_ENCRYPT); +} + +static void blowfish_decrypt(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV){ + BF_cbc_encrypt(in,out,len,cipher->key,IV,BF_DECRYPT); +} +#endif +#ifdef HAS_AES +static void aes_set_encrypt_key(struct crypto_struct *cipher, void *key){ + if(!cipher->key){ + alloc_key(cipher); + AES_set_encrypt_key(key,cipher->keysize,cipher->key); + } +} +static void aes_set_decrypt_key(struct crypto_struct *cipher, void *key){ + if(!cipher->key){ + alloc_key(cipher); + AES_set_decrypt_key(key,cipher->keysize,cipher->key); + } +} +static void aes_encrypt(struct crypto_struct *cipher, void *in, void *out, unsigned long len, void *IV){ + AES_cbc_encrypt(in,out,len,cipher->key,IV,AES_ENCRYPT); +} +static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out, unsigned long len, void *IV){ + AES_cbc_encrypt(in,out,len,cipher->key,IV,AES_DECRYPT); +} +#endif + +static void des3_set_key(struct crypto_struct *cipher, void *key){ + if(!cipher->key){ + alloc_key(cipher); + DES_set_odd_parity(key); + DES_set_odd_parity(key+8); + DES_set_odd_parity(key+16); + DES_set_key_unchecked(key,cipher->key); + DES_set_key_unchecked(key+8,cipher->key+sizeof(DES_key_schedule)); + DES_set_key_unchecked(key+16,cipher->key+2*sizeof(DES_key_schedule)); + } +} + +static void des3_encrypt(struct crypto_struct *cipher, void *in, void *out, + unsigned long len, void *IV){ + DES_ede3_cbc_encrypt(in,out,len,cipher->key,cipher->key+sizeof(DES_key_schedule),cipher->key+2*sizeof(DES_key_schedule),IV,1); +} + +static void des3_decrypt(struct crypto_struct *cipher, void *in, void *out, + unsigned long len, void *IV){ + DES_ede3_cbc_encrypt(in,out,len,cipher->key,cipher->key+sizeof(DES_key_schedule),cipher->key+2*sizeof(DES_key_schedule),IV,0); +} + +static void des3_1_encrypt(struct crypto_struct *cipher, void *in, void *out, + unsigned long len, void *IV){ +#ifdef DEBUG_CRYPTO + ssh_print_hexa("encrypt IV before",IV,24); +#endif + DES_ncbc_encrypt(in,out,len, cipher->key, IV, 1); + DES_ncbc_encrypt(out,in,len, cipher->key + sizeof(DES_key_schedule), + IV+8,0); + DES_ncbc_encrypt(in,out,len, cipher->key + 2*sizeof(DES_key_schedule), + IV+16,1); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("encrypt IV after",IV,24); +#endif +} + +static void des3_1_decrypt(struct crypto_struct *cipher, void *in, void *out, + unsigned long len, void *IV){ +#ifdef DEBUG_CRYPTO + ssh_print_hexa("decrypt IV before",IV,24); +#endif + DES_ncbc_encrypt(in,out,len, cipher->key + 2*sizeof(DES_key_schedule), + IV, 0); + DES_ncbc_encrypt(out,in,len, cipher->key + sizeof(DES_key_schedule), + IV+8,1); + DES_ncbc_encrypt(in,out,len, cipher->key, + IV+16,0); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("decrypt IV after",IV,24); +#endif +} + + + + +/* the table of supported ciphers */ +static struct crypto_struct ssh_ciphertab[]={ +#ifdef HAS_BLOWFISH + { "blowfish-cbc", 8 ,sizeof (BF_KEY),NULL,128,blowfish_set_key, + blowfish_set_key,blowfish_encrypt, blowfish_decrypt}, +#endif +#ifdef HAS_AES + { "aes128-cbc",16,sizeof(AES_KEY),NULL,128,aes_set_encrypt_key, + aes_set_decrypt_key,aes_encrypt,aes_decrypt}, + { "aes192-cbc",16,sizeof(AES_KEY),NULL,192,aes_set_encrypt_key, + aes_set_decrypt_key,aes_encrypt,aes_decrypt}, + { "aes256-cbc",16,sizeof(AES_KEY),NULL,256,aes_set_encrypt_key, + aes_set_decrypt_key,aes_encrypt,aes_decrypt}, +#endif + { "3des-cbc",8,sizeof(DES_key_schedule)*3,NULL,192,des3_set_key, + des3_set_key,des3_encrypt, des3_decrypt}, + { "3des-cbc-ssh1",8,sizeof(DES_key_schedule)*3,NULL,192,des3_set_key, + des3_set_key,des3_1_encrypt, des3_1_decrypt}, + { NULL,0,0,NULL,0,NULL,NULL,NULL} +}; +#endif /* OPENSSL_CRYPTO */ + +/* it allocates a new cipher structure based on its offset into the global table */ +struct crypto_struct *cipher_new(int offset){ + struct crypto_struct *cipher=malloc(sizeof(struct crypto_struct)); + /* note the memcpy will copy the pointers : so, you shouldn't free them */ + memcpy(cipher,&ssh_ciphertab[offset],sizeof(*cipher)); + return cipher; +} + +void cipher_free(struct crypto_struct *cipher){ + if(cipher->key){ + // destroy the key + memset(cipher->key,0,cipher->keylen); + free(cipher->key); + } + free(cipher); +} + +CRYPTO *crypto_new(){ + CRYPTO *crypto=malloc(sizeof (CRYPTO)); + memset(crypto,0,sizeof(*crypto)); + return crypto; +} + +void crypto_free(CRYPTO *crypto){ + if(crypto->server_pubkey) + free(crypto->server_pubkey); + if(crypto->in_cipher) + cipher_free(crypto->in_cipher); + if(crypto->out_cipher) + cipher_free(crypto->out_cipher); + if(crypto->e) + bignum_free(crypto->e); + if(crypto->f) + bignum_free(crypto->f); + if(crypto->x) + bignum_free(crypto->x); + if(crypto->k) + bignum_free(crypto->k); + /* lot of other things */ + /* i'm lost in my own code. good work */ + memset(crypto,0,sizeof(*crypto)); + free(crypto); +} + +static int crypt_set_algorithms2(SSH_SESSION *session){ + /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */ + int i=0; + /* out */ + char *wanted=session->client_kex.methods[SSH_CRYPT_C_S]; + while(ssh_ciphertab[i].name && strcmp(wanted,ssh_ciphertab[i].name)) + i++; + if(!ssh_ciphertab[i].name){ + ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",wanted); + return -1; + } + ssh_say(2,"Set output algorithm %s\n",wanted); + session->next_crypto->out_cipher=cipher_new(i); + i=0; + /* in */ + wanted=session->client_kex.methods[SSH_CRYPT_S_C]; + while(ssh_ciphertab[i].name && strcmp(wanted,ssh_ciphertab[i].name)) + i++; + if(!ssh_ciphertab[i].name){ + ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",wanted); + return -1; + } + ssh_say(2,"Set input algorithm %s\n",wanted); + session->next_crypto->in_cipher=cipher_new(i); + + /* compression */ + if(strstr(session->client_kex.methods[SSH_COMP_C_S],"zlib")) + session->next_crypto->do_compress_out=1; + if(strstr(session->client_kex.methods[SSH_COMP_S_C],"zlib")) + session->next_crypto->do_compress_in=1; + return 0; +} + +static int crypt_set_algorithms1(SSH_SESSION *session){ + int i=0; + /* right now, we force 3des-cbc to be taken */ + while(ssh_ciphertab[i].name && strcmp(ssh_ciphertab[i].name,"3des-cbc-ssh1")) + ++i; + if(!ssh_ciphertab[i].name){ + ssh_set_error(NULL,SSH_FATAL,"cipher 3des-cbc-ssh1 not found !"); + return -1; + } + session->next_crypto->out_cipher=cipher_new(i); + session->next_crypto->in_cipher=cipher_new(i); + return 0; +} + +int crypt_set_algorithms(SSH_SESSION *session){ + return session->version==1?crypt_set_algorithms1(session): + crypt_set_algorithms2(session); +} + diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 00000000..614ef33d --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1 2000/05/20 05:33:45 damien Exp $ + +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 diff --git a/sample.c b/sample.c new file mode 100644 index 00000000..42ae09d1 --- /dev/null +++ b/sample.c @@ -0,0 +1,434 @@ +/* client.c */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +domain. This does not apply to the rest of the library though, but it is +allowed to cut-and-paste working code from this file to any license of +program. +The goal is to show the API in action. It's not a reference on how terminal +clients must be made or how a client should react. +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAXCMD 10 +char *host; +char *user; +int sftp; +char *cmds[MAXCMD]; +struct termios terminal; +void do_sftp(SSH_SESSION *session); + +void add_cmd(char *cmd){ + int n; + for(n=0;cmds[n] && (nname,file->permissions,file->uid,file->gid,file->size); + sftp_attributes_free(file); + } + /* when file=NULL, an error has occured OR the directory listing is end of file */ + if(!sftp_dir_eof(dir)){ + ssh_say(0,"error : %s\n",ssh_get_error(session)); + return; + } + if(sftp_dir_close(dir)){ + ssh_say(0,"Error : %s\n",ssh_get_error(session)); + return; + } + /* this will open a file and copy it into your /home directory */ + /* the small buffer size was intended to stress the library. of course, you can use a buffer till 20kbytes without problem */ + + fichier=sftp_open(sftp,"/usr/bin/ssh",O_RDONLY,NULL); + if(!fichier){ + ssh_say(0,"Error opening /usr/bin/ssh : %s\n",ssh_get_error(session)); + return; + } + /* open a file for writing... */ + to=sftp_open(sftp,"ssh-copy",O_WRONLY | O_CREAT,NULL); + if(!to){ + ssh_say(0,"Error opening ssh-copy for writing : %s\n",ssh_get_error(session)); + return; + } + while((len=sftp_read(fichier,data,4096)) > 0){ + if(sftp_write(to,data,len)!=len){ + ssh_say(0,"error writing %d bytes : %s\n",len,ssh_get_error(session)); + return; + } + } + printf("finished\n"); + if(len<0) + ssh_say(0,"Error reading file : %s\n",ssh_get_error(session)); + sftp_file_close(fichier); + sftp_file_close(to); + printf("fichiers fermés\n"); + to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT,NULL); + for(i=0;i<1000;++i){ + len=sftp_write(to,data,8000); + printf("wrote %d bytes\n",len); + if(len != 8000){ + printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session)); + } + } + sftp_file_close(to); + /* close the sftp session */ + sftp_free(sftp); + printf("session sftp terminée\n"); +} + +int auth_kbdint(SSH_SESSION *session){ + int err=ssh_userauth_kbdint(session,NULL,NULL); + char *name,*instruction,*prompt,*ptr; + char buffer[128]; + int i,n; + char echo; + while (err==SSH_AUTH_INFO){ + name=ssh_userauth_kbdint_getname(session); + instruction=ssh_userauth_kbdint_getinstruction(session); + n=ssh_userauth_kbdint_getnprompts(session); + if(strlen(name)>0) + printf("%s\n",name); + if(strlen(instruction)>0) + printf("%s\n",instruction); + for(i=0;i +#include +#include +int main(int argc, char **argv){ +#ifdef WITH_SERVER + SSH_OPTIONS *opts=ssh_getopt(&argc,argv); + SSH_SESSION *server=getserver(opts); + if(!server){ + printf("pwned : %s\n",ssh_get_error(NULL)); + exit(-1); + } + server->clientbanner=ssh_get_banner(server); + if(!server->clientbanner){ + printf("%s\n",ssh_get_error(NULL)); + return -1; + } + server_set_kex(server); + send_kex(server,1); + if (ssh_get_kex(server,1)){ + printf("%s \n",ssh_get_error(NULL)); + return -1; + } + list_kex(&server->client_kex); + + while(1); +#endif + return 0; +} diff --git a/ssh1/auth1.c b/ssh1/auth1.c new file mode 100644 index 00000000..d92f50cc --- /dev/null +++ b/ssh1/auth1.c @@ -0,0 +1,202 @@ +/* auth1.c deals with authentication with SSH-1 protocol */ +/* +Copyright 2005 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "libssh/priv.h" +#include "libssh/ssh1.h" +#include +#include + +/* +static void burn(char *ptr){ + if(ptr) + memset(ptr,'X',strlen(ptr)); +} +*/ +#ifdef HAVE_SSH1 +static int wait_auth1_status(SSH_SESSION *session){ + /* wait for a packet */ + if(packet_read(session)) + return SSH_AUTH_ERROR; + if(packet_translate(session)) + return SSH_AUTH_ERROR; + switch(session->in_packet.type){ + case SSH_SMSG_SUCCESS: + return SSH_AUTH_SUCCESS; + case SSH_SMSG_FAILURE: + return SSH_AUTH_DENIED; + } + ssh_set_error(session,SSH_FATAL,"Was waiting for a SUCCESS or " + "FAILURE, got %d",session->in_packet.type); + return SSH_AUTH_ERROR; +} +static int send_username(SSH_SESSION *session, char *username){ + STRING *user; + /* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */ + if(session->auth_service_asked) + return session->auth_service_asked; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_USER); + if(!username) + if(!(username=session->options->username)){ + if(options_default_username(session->options)) + return session->auth_service_asked=SSH_AUTH_ERROR; + else + username=session->options->username; + } + user=string_from_char(username); + buffer_add_ssh_string(session->out_buffer,user); + free(user); + packet_send(session); + session->auth_service_asked=wait_auth1_status(session); + return session->auth_service_asked; +} + +/* use the "none" authentication question */ + +int ssh_userauth1_none(SSH_SESSION *session,char *username){ + return send_username(session,username); +} + +/* +int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey){ + STRING *user; + STRING *service; + STRING *method; + STRING *algo; + int err=SSH_AUTH_ERROR; + if(!username) + if(!(username=session->options->username)){ + if(options_default_username(session->options)) + return SSH_AUTH_ERROR; + else + username=session->options->username; + } + if(ask_userauth(session)) + return SSH_AUTH_ERROR; + user=string_from_char(username); + service=string_from_char("ssh-connection"); + method=string_from_char("publickey"); + algo=string_from_char(ssh_type_to_char(type)); + + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); + buffer_add_ssh_string(session->out_buffer,user); + buffer_add_ssh_string(session->out_buffer,service); + buffer_add_ssh_string(session->out_buffer,method); + buffer_add_u8(session->out_buffer,0); + buffer_add_ssh_string(session->out_buffer,algo); + buffer_add_ssh_string(session->out_buffer,publickey); + packet_send(session); + err=wait_auth_status(session,0); + free(user); + free(method); + free(service); + free(algo); + return err; +} +*/ +int ssh_userauth1_offer_pubkey(SSH_SESSION *session, char *username, int type, + STRING *pubkey){ + return SSH_AUTH_DENIED; +} + +/* +int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey){ + STRING *user; + STRING *service; + STRING *method; + STRING *algo; + STRING *sign; + int err=SSH_AUTH_ERROR; + if(!username) + if(!(username=session->options->username)){ + if(options_default_username(session->options)) + return err; + else + username=session->options->username; + } + if(ask_userauth(session)) + return err; + user=string_from_char(username); + service=string_from_char("ssh-connection"); + method=string_from_char("publickey"); + algo=string_from_char(ssh_type_to_char(privatekey->type)); + + +*/ /* we said previously the public key was accepted */ +/* packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); + buffer_add_ssh_string(session->out_buffer,user); + buffer_add_ssh_string(session->out_buffer,service); + buffer_add_ssh_string(session->out_buffer,method); + buffer_add_u8(session->out_buffer,1); + buffer_add_ssh_string(session->out_buffer,algo); + buffer_add_ssh_string(session->out_buffer,publickey); + sign=ssh_do_sign(session,session->out_buffer,privatekey); + if(sign){ + buffer_add_ssh_string(session->out_buffer,sign); + free(sign); + packet_send(session); + err=wait_auth_status(session,0); + } + free(user); + free(service); + free(method); + free(algo); + return err; +} +*/ + +int ssh_userauth1_password(SSH_SESSION *session,char *username,char *password){ + STRING *password_s; + int err; + err=send_username(session,username); + if(err!=SSH_AUTH_DENIED) + return err; + /* we trick a bit here. A known flaw in SSH1 protocol is that it's + * easy to guess password sizes. + * not that sure ... + */ + if(strlen(password)>=128){ + /* not risky to disclose the size of such a big password .. */ + password_s=string_from_char(password); + } else { + /* fill the password string from random things. the strcpy + * ensure there is at least a nul byte after the password. + * most implementation won't see the garbage at end. + * why garbage ? because nul bytes will be compressed by + * gzip and disclose password len. + */ + password_s=string_new(128); + ssh_get_random(password_s->string,128); + strcpy(password_s->string,password); + } + + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_AUTH_PASSWORD); + buffer_add_ssh_string(session->out_buffer,password_s); + string_burn(password_s); + free(password_s); + packet_send(session); + return wait_auth1_status(session); +} + +#endif /* HAVE_SSH1 */ diff --git a/ssh1/channels1.c b/ssh1/channels1.c new file mode 100644 index 00000000..eecfdb0a --- /dev/null +++ b/ssh1/channels1.c @@ -0,0 +1,244 @@ +/* channels1.c */ +/* Support for SSH-1 type channels */ +/* +Copyright 2005 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include + +#include "libssh/priv.h" +#include "libssh/ssh1.h" + +#ifdef HAVE_SSH1 + +/* this is a big hack. In fact, SSH-1 doesn't make a clever use of channels. + * The whole packets concerning Shells are sent outside of a channel. + * Thus, an inside limitation of this behaviour is that you can't only + * request one Shell. + * And i don't even know yet how they managed to imbed two "channel" + * into one protocol. + */ + +CHANNEL *channel_open_session1(SSH_SESSION *session){ + CHANNEL *chan; + // we guess we are requesting an *exec* channel. It can only have + // only one exec channel. so we abort with an error if we need more than + // one. + if(session->exec_channel_opened){ + ssh_set_error(session,SSH_REQUEST_DENIED,"SSH-1 supports only one execution channel. One has already been opened"); + return NULL; + } + session->exec_channel_opened=1; + chan=channel_new(session); + chan->open=1; + ssh_say(2,"Opened a ssh1 channel session\n"); + return chan; +} +/* 10 SSH_CMSG_REQUEST_PTY + * + * string TERM environment variable value (e.g. vt100) + * 32-bit int terminal height, rows (e.g., 24) + * 32-bit int terminal width, columns (e.g., 80) + * 32-bit int terminal width, pixels (0 if no graphics) (e.g., 480) + * 32-bit int terminal height, pixels (0 if no graphics) (e.g., 640) + * n bytes tty modes encoded in binary + * Some day, someone should have a look at that nasty tty encoded. It's + * much simplier under ssh2. I just hope the defaults values are ok ... + */ + +int channel_request_pty_size1(CHANNEL *channel, char *terminal, int col, + int row){ + STRING *str; + SSH_SESSION *session=channel->session; + str=string_from_char(terminal); + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_REQUEST_PTY); + buffer_add_ssh_string(session->out_buffer,str); + free(str); + buffer_add_u32(session->out_buffer,ntohl(row)); + buffer_add_u32(session->out_buffer,ntohl(col)); + buffer_add_u32(session->out_buffer,0); /* x */ + buffer_add_u32(session->out_buffer,0); /* y */ + buffer_add_u8(session->out_buffer,0); /* tty things */ + ssh_say(2,"Opening a ssh1 pty\n"); + if(packet_send(session)) + return -1; + if(packet_read(session)) + return -1; + if(packet_translate(session)) + return -1; + switch (session->in_packet.type){ + case SSH_SMSG_SUCCESS: + ssh_say(2,"pty : Success\n"); + return 0; + break; + case SSH_SMSG_FAILURE: + ssh_set_error(session,SSH_REQUEST_DENIED, + "Server denied PTY allocation"); + ssh_say(2,"pty : denied\n"); + break; + default: + ssh_say(2,"pty : error\n"); + ssh_set_error(session,SSH_FATAL, + "Received unexpected packet type %d", + session->in_packet.type); + return -1; + } + return -1; +} + +int channel_change_pty_size1(CHANNEL *channel, int cols, int rows){ + SSH_SESSION *session=channel->session; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_WINDOW_SIZE); + buffer_add_u32(session->out_buffer,ntohl(rows)); + buffer_add_u32(session->out_buffer,ntohl(cols)); + buffer_add_u32(session->out_buffer,0); + buffer_add_u32(session->out_buffer,0); + if(packet_send(session)) + return -1; + ssh_say(2,"Change pty size send\n"); + packet_wait(session,SSH_SMSG_SUCCESS,1); + switch (session->in_packet.type){ + case SSH_SMSG_SUCCESS: + ssh_say(2,"pty size changed\n"); + return 0; + break; + case SSH_SMSG_FAILURE: + ssh_say(2,"pty size change denied\n"); + ssh_set_error(session,SSH_REQUEST_DENIED,"pty size change denied"); + return -1; + } + ssh_set_error(session,SSH_FATAL,"Received unexpected packet type %d", + session->in_packet.type); + return -1; +} + +int channel_request_shell1(CHANNEL *channel){ + SSH_SESSION *session=channel->session; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL); + if(packet_send(session)) + return -1; + ssh_say(2,"Launched a shell\n"); + return 0; +} + +int channel_request_exec1(CHANNEL *channel, char *cmd){ + SSH_SESSION *session=channel->session; + STRING *command=string_from_char(cmd); + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_CMD); + buffer_add_ssh_string(session->out_buffer,command); + free(command); + if(packet_send(session)) + return -1; + ssh_say(2,"executing %s...\n",cmd); + return 0; +} + +static void channel_rcv_data1(SSH_SESSION *session, int is_stderr){ + CHANNEL *channel; + STRING *str; + channel=session->channels; // Easy. hack this when multiple channel + // are comming + str=buffer_get_ssh_string(session->in_buffer); + if(!str){ + ssh_say(0,"Invalid data packet !\n"); + return; + } + ssh_say(3,"adding %d bytes data in %d\n",string_len(str),is_stderr); + if(!is_stderr){ + /* stdout */ + if(channel->write_fct){ + channel->write_fct(channel,str->string,string_len(str), + channel->userarg); + } else { + channel_default_bufferize(channel,str->string,string_len(str), + is_stderr); + } + } else { + /* stderr */ + if(channel->write_err_fct){ + channel->write_err_fct(channel,str->string,string_len(str), + channel->userarg); + } else { + channel_default_bufferize(channel,str->string,string_len(str), + is_stderr); + } + } + free(str); +} + +static void channel_rcv_close1(SSH_SESSION *session){ + CHANNEL *channel=session->channels; + u32 status; + buffer_get_u32(session->in_buffer,&status); + /* it's much more than a channel closing. spec says it's the last + * message sent by server (strange) + */ + /* actually status is lost somewhere */ + channel->open=0; + channel->remote_eof=1; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_EXIT_CONFIRMATION); + packet_send(session); +} + +void channel_handle1(SSH_SESSION *session, int type){ + ssh_say(3,"Channel_handle1(%d)\n",type); + switch (type){ + case SSH_SMSG_STDOUT_DATA: + channel_rcv_data1(session,0); + break; + case SSH_SMSG_EXITSTATUS: + channel_rcv_close1(session); + break; + default: + ssh_say(0,"Unexepected message %d\n",type); + + } +} + +int channel_write1(CHANNEL *channel, void *data, int len){ + SSH_SESSION *session=channel->session; + int origlen=len; + int effectivelen; + while(len>0){ + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH_CMSG_STDIN_DATA); + if(len > 32000) + effectivelen=32000; + else + effectivelen=len; + buffer_add_u32(session->out_buffer,htonl(effectivelen)); + buffer_add_data(session->out_buffer,data,effectivelen); + data+=effectivelen; + len-=effectivelen; + if(packet_send(session)) + return -1; + } + return origlen; +} + +#endif /* HAVE_SSH1 */