mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
first import
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@1 7dcaeef0-15fb-0310-b436-a5af3365683c
This commit is contained in:
5
AUTHORS
Normal file
5
AUTHORS
Normal file
@@ -0,0 +1,5 @@
|
||||
Author(s):
|
||||
Aris Adamantiadis (aka spacewalker) <aris@0xbadc0de.be>
|
||||
|
||||
Contributor(s):
|
||||
Nick Zitzmann <seiryu (at) comcast (dot) net>
|
||||
80
CHANGELOG
Normal file
80
CHANGELOG
Normal file
@@ -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.
|
||||
504
COPYING
Normal file
504
COPYING
Normal file
@@ -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.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
266
Doxyfile
Normal file
266
Doxyfile
Normal file
@@ -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
|
||||
79
Makefile.in
Normal file
79
Makefile.in
Normal file
@@ -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"
|
||||
|
||||
39
README
Normal file
39
README
Normal file
@@ -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
|
||||
1415
config.guess
vendored
Executable file
1415
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
172
config.h.in
Normal file
172
config.h.in
Normal file
@@ -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 <fcntl.h> 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 <inttypes.h> 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 <memory.h> 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 <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
||||
#undef HAVE_OPENSSL_AES_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/blowfish.h> 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 <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> 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 <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> 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 <sys/poll.h> header file. */
|
||||
#undef HAVE_SYS_POLL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#undef HAVE_TERMIOS_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> 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 <zlib.h> 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 <sys/time.h> and <time.h>. */
|
||||
#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
|
||||
1510
config.sub
vendored
Executable file
1510
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
60
configure.in
Normal file
60
configure.in
Normal file
@@ -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
|
||||
886
doc/API.html
Normal file
886
doc/API.html
Normal file
@@ -0,0 +1,886 @@
|
||||
<!DOCTYPE HTML SYSTEM>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
|
||||
<head>
|
||||
<title>
|
||||
Libssh's Documentation
|
||||
</title>
|
||||
<link href="style.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
|
||||
<div id="titre">
|
||||
<div align="center">
|
||||
LIBSSH API GUIDE <br>
|
||||
Or everything you ever wanted to know about a simple and fast ssh library.
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2> 0 Introduction</h2>
|
||||
|
||||
<div class="tout">
|
||||
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. <br>
|
||||
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.<br>
|
||||
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. <br>
|
||||
The SSH protocol was designed for some goals which I resume here : <br>
|
||||
-Privacy of data<br>
|
||||
-Security<br>
|
||||
-Authentication of the server<br>
|
||||
-Authentication of the client.<br>
|
||||
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:<br>
|
||||
<br>
|
||||
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.<br>
|
||||
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.<br>
|
||||
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.<br>
|
||||
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.<br>
|
||||
5- With the channel you opened, you can do several things :<br>
|
||||
-Open a shell. You may want to request a pseudo virtual terminal before <br>
|
||||
-Execute a command. The virtual terminal is usable, too<br>
|
||||
-Invoke the sftp subsystem. (look at chapter 6)<br>
|
||||
-invoke your own subsystem. This is out the scope of this
|
||||
document but it is easy to do.<br>
|
||||
6- When everything is finished, just close the channels, and then the
|
||||
connection.<br>
|
||||
<br>
|
||||
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 :)
|
||||
<br>
|
||||
</div>
|
||||
<h2> 1- Setting the options </h2>
|
||||
<div class="tout">
|
||||
The options mechanism will change during updates of the library, but the
|
||||
functions which exists now will certainly be kept.
|
||||
<br><br>
|
||||
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, ... <br>
|
||||
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.<br>
|
||||
Two ways are given for setting the options : the easy one (of course !) and
|
||||
the long-but-accurate one.<br><br>
|
||||
</div>
|
||||
<h3>a) the easy way</h3><br>
|
||||
<div class="tout">
|
||||
Lot of ssh options in fact come from the command line of the program... <br>
|
||||
you could parse them and then use the long way for every argument, but libssh
|
||||
has a mechanism to do that for you, automatically.<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv);
|
||||
</div>
|
||||
this function will return you a new options pointer based on the arguments
|
||||
you give in parameters. <br> better, they clean the argv array from used parameters
|
||||
so you can use them after in your own program<br>
|
||||
<div class="ex">
|
||||
int main(int argc, char **argv){<br>
|
||||
SSH_OPTIONS *opt;<br>
|
||||
opt=ssh_getopt(&argc, argv);<br>
|
||||
if(!opt){<br>
|
||||
...<br>
|
||||
}<br>
|
||||
</div>
|
||||
the function will return NULL if some problem is appearing.<br>
|
||||
As a matter of portability for you own programs, the hostname isn't always<br>
|
||||
the first argument from the command line, so the single arguments (not
|
||||
preceded by a -something) won't be parsed.<br>
|
||||
<div class="ex">
|
||||
example: <br>
|
||||
user@host:~$ myssh -u aris localhost <br>
|
||||
-u aris will be caught, localhost will not.<br>
|
||||
</div>
|
||||
|
||||
cfr the options_set_user() function in the next part for more informations
|
||||
about it.<br>
|
||||
</div>
|
||||
<h3>b) the long way</h3>
|
||||
<div class="tout">
|
||||
<div class="prot">
|
||||
SSH_OPTIONS *options_new();
|
||||
</div>
|
||||
This function returns an empty but initialized option structure pointer.<br>
|
||||
The structure is freed by ssh_disconnect described later, so don't use the
|
||||
existing function options_free() (it's an internal function).<br>
|
||||
So : use it only for <b>one</b> ssh_connect(), <b>never</b> free it.<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
SSH_OPTIONS *options_copy(SSH_OPTIONS *opt);
|
||||
</div>
|
||||
If you need to replicate an option object before using it, use this function.
|
||||
<br><br>
|
||||
|
||||
The following functions are all of the following form : <br>
|
||||
<div class="prot">
|
||||
int options_set_something(SSH_OPTIONS *opt, something);
|
||||
</div>
|
||||
the something parameters are always internaly copied, so you don't have to
|
||||
strdup them.<br>
|
||||
some return eather 0 or -1, in which case an error message appears in the
|
||||
error functions, others never fail (return void)<br>
|
||||
the error codes and descriptions for these functions are recoverable throught <i>ssh_get_error(NULL);</i>
|
||||
<br>
|
||||
<div class="prot">
|
||||
int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list);
|
||||
</div>
|
||||
Passing an option structure, a ssh macro for the method, and a list of allowed
|
||||
parameters indicates libssh you want to use these.<br>
|
||||
The macros are :<br>
|
||||
KEX_ALGO<br>
|
||||
KEX_HOSTKEY Server public key type expected<br>
|
||||
KEX_CRYPT_C_S 2 Cryptographic algorithm client->server<br>
|
||||
KEX_CRYPT_S_C 3 Cryptographic algorithm server->client<br>
|
||||
KEX_MAC_C_S 4<br>
|
||||
KEX_MAC_S_C 5<br>
|
||||
KEX_COMP_C_S 6 Compression method for the stream ("zlib" or "none"), client to server<br>
|
||||
KEX_COMP_S_C 7 Compression method for the stream ("zlib" or "none"), server to client<br>
|
||||
KEX_LANG_C_S 8<br>
|
||||
KEX_LANG_S_C 9<br>
|
||||
<br>
|
||||
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.<br>
|
||||
<br>
|
||||
<div class="ex">
|
||||
example : this sets the ssh stream to be compressed in client->server mode only
|
||||
<br>
|
||||
|
||||
ret = option_set_wanted_method(options,KEX_COMP_C_S,"zlib");
|
||||
</div>
|
||||
<div class="ex">
|
||||
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:<br>
|
||||
ret = option_set_wanted_method(options,KEX_CRYPT_S_C,"aes128-cbc,aes192-cbc");
|
||||
</div>
|
||||
<div class="ex">
|
||||
if you prefer getting the Dss key from a server instead of rsa, but you still
|
||||
accept rsa if dss isn't available :<br>
|
||||
options_set_wanted_method(options,KEX_HOSTKEY,"ssh-dss,ssh-rsa");
|
||||
</div>
|
||||
return value: <br>0 if the option is valid, -1 else.<br> An error is set in that case.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void options_set_port(SSH_OPTIONS *opt, unsigned int port);
|
||||
</div>
|
||||
this function sets the server port.
|
||||
<div class="prot">
|
||||
void options_set_host(SSH_OPTIONS *opt, const char *hostname);
|
||||
</div>
|
||||
this function sets the hostname of the server. It also supports
|
||||
"user@hostname" syntax in which case the user options is set too.
|
||||
<div class="prot">
|
||||
void options_set_fd(SSH_OPTIONS *opt, int fd);
|
||||
</div>
|
||||
permits you to specify an opened file descriptor you've opened yourself.
|
||||
<br>
|
||||
It's a good way of bypassing the internal FD opening in libssh, but there are things you should take care of : <br>
|
||||
-The file descriptor should be returned to libssh without nonblocking settings<br>
|
||||
-If you wish to use <i>is_server_known()</i> You should also set <i>options_set_host</i>... Otherwise libssh won't have any mean of certifying the server is known or not.<br><br>
|
||||
<div class="prot">
|
||||
void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr);
|
||||
</div>
|
||||
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
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void options_set_username(SSH_OPTIONS *opt,char *username);
|
||||
</div>
|
||||
sets username for authenticating in this session.
|
||||
<br><br>
|
||||
|
||||
<div class="prot">
|
||||
void option_set_timeout(SSH_OPTIONS *opt,long seconds, long usec);
|
||||
</div>
|
||||
sets the timeout for connecting to the socket. It does not include a timeout for the name resolving or handshake.
|
||||
<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir);
|
||||
</div>
|
||||
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.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir);
|
||||
</div>
|
||||
same than <i>options_set_ssh_dir()</i> for known_hosts file.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void options_set_identity(SSH_OPTIONS *opt, char *identity);
|
||||
</div>
|
||||
same than upper for the identity file (they come by pair, the one asked is the file without the .pub suffix)
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg);
|
||||
</div>
|
||||
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
|
||||
<div class="prot">void function(void *userarg, float status);</div> with status going from 0 to 1 during ssh_connect. The callback won't ever be called after the connection is made.
|
||||
<br><br>
|
||||
</div>
|
||||
<h2>
|
||||
2- Connecting the ssh server
|
||||
</H2>
|
||||
<div class="tout">
|
||||
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.
|
||||
<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
SSH_SESSION *ssh_connect(SSH_OPTIONS *options);
|
||||
</div>
|
||||
This function returns a handle on the newly connection. This function expects
|
||||
to have a pre-set options structure.
|
||||
<br>
|
||||
It returns NULL in case of error, in which case you can look at error messages
|
||||
for more informations.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void ssh_disconnect(SSH_SESSION *session);
|
||||
</div>
|
||||
This function sends a polite disconnect message, and does clean the session.<br>
|
||||
This is the proper way of finishing a ssh connection.<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
int ssh_get_pubkey_hash(SSH_SESSION *session, char hash[MD5_DIGEST_LEN]);
|
||||
</div>
|
||||
This function places the MD5 hash of the server public key into the hash array.<br>
|
||||
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).
|
||||
<br>
|
||||
You can skip this step if you correctly handle <i>is_server_known()</i>
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int ssh_is_server_known(SSH_SESSION *session);
|
||||
</div>
|
||||
|
||||
Checks the user's known host file to look for a previous connection to the specified server. Return values:<br>
|
||||
SSH_SERVER_KNOWN_OK : the host is known and the key has not changed<br>
|
||||
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.<br>
|
||||
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.<br>
|
||||
IE server sent a DSA key and we had a RSA key.<br>
|
||||
Be carreful it's a possible attack (coder should use option_set_wanted_method() to specify
|
||||
which key to use).<br>
|
||||
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.<br>
|
||||
SSH_SERVER_ERROR : Some error happened while opening known host file.<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
int ssh_write_knownhost(SSH_SESSION *session);
|
||||
</div>
|
||||
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.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int pubkey_get_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
|
||||
</div>
|
||||
deprecated but left for binary compatibility (will be removed in newer versions).
|
||||
</div>
|
||||
|
||||
<h2>3- Authenticating to server</h2>
|
||||
<div class="tout">
|
||||
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).
|
||||
<br>
|
||||
|
||||
Authentication methods :<br>
|
||||
<h3>A) Public keys</h3><br>
|
||||
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).<br>
|
||||
Libssh is obviously fully compatible with the openssh public and private keys.<br>
|
||||
The things go this way : you scan a list of files which contain public keys.<br>
|
||||
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.<br>
|
||||
Here again, two ways for the public key authentication... the easy and the
|
||||
complicated one.<br>
|
||||
<br>
|
||||
<h4> easy way:</h4>
|
||||
<div class="prot">
|
||||
int ssh_userauth_autopubkey(SSH_SESSION *session);
|
||||
</div>
|
||||
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 <i>options_set_identity()</i> function.<br>
|
||||
The return values are :<br>
|
||||
SSH_AUTH_ERROR : some serious error happened during authentication<br>
|
||||
SSH_AUTH_DENIED : no key matched<br>
|
||||
SSH_AUTH_SUCCESS : you are now authenticated<br>
|
||||
SSH_AUTH_PARTIAL : some key matched but you still have to give an other mean
|
||||
of authentication (like password).<br>
|
||||
<br>
|
||||
<h4> peanful way:</h4>
|
||||
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.<br>
|
||||
<div class="prot">
|
||||
STRING *publickey_from_file(char *filename,int *_type);
|
||||
</div>
|
||||
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.<br><br>
|
||||
<div class="prot">
|
||||
int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,
|
||||
int type, STRING *publickey);
|
||||
</div>
|
||||
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.<br>
|
||||
Still watch for SSH_AUTH_ERROR as connection problems might happen.
|
||||
<br>
|
||||
in case of SSH_AUTH_SUCCESS,
|
||||
<br>
|
||||
<div class="prot">
|
||||
PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,
|
||||
int type,char *passphrase);
|
||||
</div>
|
||||
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.<br>
|
||||
The function returns NULL if the private key wasn't opened
|
||||
(ie bad passphrase or missing file).<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
int ssh_userauth_pubkey(SSH_SESSION *session, char *username,
|
||||
STRING *publickey, PRIVATE_KEY *privatekey);
|
||||
</div>
|
||||
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.<br>
|
||||
|
||||
each public key (of type STRING) must be freed with the libc "free" function.<br>
|
||||
The private key must be freed with private_key_free(PRIVATE_KEY *) which
|
||||
will clean the memory before (don't worry about passphrase leaking).<br>
|
||||
<br>
|
||||
|
||||
<h3> B) Password</h3><br>
|
||||
<div class="prot">
|
||||
int ssh_userauth_password(SSH_SESSION *session,char *username,char *password);
|
||||
</div>
|
||||
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.<br><br>
|
||||
|
||||
<h3> C) Keyboard-interactive</h3><br>
|
||||
<div class="prot">
|
||||
int ssh_userauth_kbdint(SSH_SESSION *session, char *user, char *submethods);
|
||||
</div>
|
||||
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.<br>
|
||||
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.<br>
|
||||
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.<br>
|
||||
Few remarks :<br>
|
||||
-Even the first call can return SSH_AUTH_DENIED or SSH_AUTH_SUCCESS.<br>
|
||||
-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<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session);
|
||||
</div>
|
||||
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.<br>
|
||||
It could be zero, in which case you must act as said previously.<br>
|
||||
|
||||
<div class="prot">
|
||||
char *ssh_userauth_kbdint_getname(SSH_SESSION *session);
|
||||
</div>
|
||||
this functions returns the "name" of the message block. The meaning is explained later.<br>
|
||||
This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.<br>
|
||||
|
||||
<div class="prot">
|
||||
char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session);
|
||||
</div>
|
||||
this functions returns the "instruction" of the message block. The meaning is explained later.<br>
|
||||
This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.<br>
|
||||
|
||||
<div class="prot">
|
||||
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session,int i, char *echo);
|
||||
</div>
|
||||
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.<br>
|
||||
zero means that the echo is Off (like for a password prompt).<br>
|
||||
any other value means the echo is on.<br>
|
||||
This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.<br>
|
||||
|
||||
<div class="prot">
|
||||
void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *a
|
||||
nswer);
|
||||
</div>
|
||||
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.<br>
|
||||
care must be taken so you discard the content of the original string after this function call.<br>
|
||||
|
||||
<h3> A little note about how to use the informations from keyboard-interactive authentication</h3>
|
||||
<br>
|
||||
The words from the original drafts explain everything
|
||||
<div class="prot">
|
||||
3.3 User Interface
|
||||
|
||||
Upon receiving a request message, the client SHOULD prompt the user
|
||||
as follows:<br>
|
||||
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.<br>
|
||||
<br>
|
||||
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.<br>
|
||||
<br>
|
||||
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.<br>
|
||||
The instruction field SHOULD NOT be truncated.<br>
|
||||
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.<br>
|
||||
<br>
|
||||
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.<br>
|
||||
|
||||
</div>
|
||||
<br>
|
||||
<h3> D) "none"</h3><br>
|
||||
In fact this mode only serve to get the list of supported authentications.<br>
|
||||
however, it also serves to get the banner message from the server, if any.<br>
|
||||
You should firstly try this method, at least for getting the banner, then to enter if there is no password at all.<br>
|
||||
<div class="prot">
|
||||
int ssh_userauth_none(SSH_SESSION *session, char *username);
|
||||
</div>
|
||||
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.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
char *ssh_get_issue_banner(SSH_SESSION *session);
|
||||
</div>
|
||||
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.<br><br>
|
||||
</div>
|
||||
|
||||
<h2>4- Opening a channel</h2>
|
||||
<div class="tout">
|
||||
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.<br>
|
||||
You probably want to open one or more shells, or call one or more programs.<br>
|
||||
|
||||
So you need a channel.<br>
|
||||
<div class="prot">
|
||||
CHANNEL *channel;
|
||||
</div>
|
||||
This is an handler to a channel object. it describes your channel.
|
||||
<br>
|
||||
<div class="prot">
|
||||
CHANNEL *channel_open_session(SSH_SESSION *session);
|
||||
</div>
|
||||
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).<br>
|
||||
The function returns NULL if for a reason or another the channel can't be
|
||||
opened.<br>
|
||||
<i>
|
||||
CHANNEL *open_session_channel(...)</i> is deprecated and should not be used in future
|
||||
applications.<br><br>
|
||||
<div class="prot">
|
||||
CHANNEL *channel_open_forward(SSH_SESSION *session, char *remotehost,
|
||||
int remoteport, char *sourcehost, int localport);
|
||||
</div>
|
||||
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.<br>
|
||||
Otherwise, NULL will be returned. sourcehost and localport are generaly
|
||||
used in message debugging purpose and have no effect on the result.<br>
|
||||
<br>
|
||||
When you've finished with your channel, you may send an EOF message and
|
||||
then close it :<br>
|
||||
<div class="prot">
|
||||
void channel_send_eof(CHANNEL *channel);
|
||||
</div>
|
||||
sends an end of file into channel. It doesn't close the channel and you can still read it.<br><br>
|
||||
|
||||
<div class="prot">
|
||||
void channel_free(CHANNEL *channel);
|
||||
</div>
|
||||
closes and destroy the channel.
|
||||
<br>
|
||||
<div class="prot">
|
||||
void channel_close(CHANNEL *channel);
|
||||
</div>
|
||||
sends an EOF and close the channel. (if you don't know what to do, use channel_free). It doesn't free the channel.
|
||||
|
||||
</div>
|
||||
<h2>5- The shell</h2>
|
||||
<div class="tout">
|
||||
<div class="prot">
|
||||
int channel_request_env(CHANNEL *channel, char *name, char *value);
|
||||
</div>
|
||||
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.<br><br>
|
||||
<div class="prot">
|
||||
int channel_request_pty(CHANNEL *channel);
|
||||
</div>
|
||||
ask the server to allocate a pseudo terminal for the current channel.<br>
|
||||
the function returns 0 on success.<br><br>
|
||||
|
||||
<div class="prot">
|
||||
int channel_request_pty_size(CHANNEL *channel, char *terminal, int cols, int rows);
|
||||
</div>
|
||||
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).<br><br>
|
||||
<div class="prot">
|
||||
int channel_change_pty_size(CHANNEL *channel, int cols,int rows);
|
||||
</div>
|
||||
changes the window size (terminal) of the current session;<br><br>
|
||||
<div class="prot">
|
||||
int channel_request_shell(CHANNEL *channel);
|
||||
</div>
|
||||
This function requests a shell. After its success, a shell is running at the other side of the channel.<br><br>
|
||||
<div class="prot">
|
||||
int channel_request_exec(CHANNEL *channel, char *cmd);
|
||||
</div>
|
||||
run a shell command without an interactive shell, ie $SHELL -c "command".<br>
|
||||
returns 0 on success.<br><br>
|
||||
|
||||
You might ask the server to open a subsystem for you. this is done this way :
|
||||
<div class="prot">
|
||||
int channel_request_subsystem(CHANNEL *channel, char *subsystem);
|
||||
</div>
|
||||
There are some functions used to manipulate the channels :
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int channel_write(CHANNEL *channel,void *data,int len);
|
||||
</div>
|
||||
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.<br><br>
|
||||
<div class="prot">
|
||||
int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr);
|
||||
</div>
|
||||
It makes a blocking read on the channel, of "bytes" bytes and returns the
|
||||
result into an allocated buffer you passed in. (with <i>buffer_new()</i>).<br>
|
||||
it will read on stderr, if is_stderr is set.<br>
|
||||
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.<br>
|
||||
with "bytes"=0, <i>channel_read()</i> 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).<br>
|
||||
|
||||
You don't need to free and allocate a new buffer each time you call this function, just pass the same object each time.<br>
|
||||
look at the <i>buffer_</i> functions further for the correct way of retrieving the data.<br><br>
|
||||
|
||||
<div class="prot">
|
||||
int channel_read_nonblocking (CHANNEL *channel, char *dest, int len, int is_stderr);
|
||||
</div>
|
||||
Non-blocking read on channel, at most len bytes of data are read. Returns 0 if EOF or if no data available.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int channel_is_open(CHANNEL *channel);
|
||||
</div>
|
||||
returns 0 if the channel has been closed by remote host, something else otherwise.<br><br>
|
||||
<div class="prot">
|
||||
int channel_poll(CHANNEL *channel, int is_stderr);
|
||||
</div>
|
||||
This nonblocking function returns the number of bytes immediatly available for
|
||||
reading on the channel and stdin/stderr.<br><br>
|
||||
|
||||
More interesting, if you are going to do channel multiplexing, this function
|
||||
is for you :<br><br>
|
||||
<div class="prot">
|
||||
int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd,
|
||||
fd_set *readfds, struct timeval *timeout);
|
||||
</div>
|
||||
channels is an array of channel pointers, finished by a NULL pointer.<br>
|
||||
It can be used ever and ever, as it is never written.<br>
|
||||
outchannels is an array of size at least greater or equal to "channels".<br>
|
||||
It hasn't to be initialized.<br>
|
||||
maxfd is the maximum file descriptor from your own filedescriptors.<br>
|
||||
readfds is a pointer to a fd_set structure, like in the original
|
||||
select implementation (man select).<br>
|
||||
the struct timeval *timeout has the same meaning than in
|
||||
select(2) (man select).<br>
|
||||
|
||||
There is no support for writing or special events as in <i>select(2)</i> yet.<br>
|
||||
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.<br>
|
||||
<b>note about signals:</b> 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 <i>ssh_select</i> during a signal.
|
||||
<br>take a look at sample.c on how to bypass that limitation.<br>
|
||||
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).<br>
|
||||
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.<br>
|
||||
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).<br>
|
||||
this is the "heart" of your main loop.<br>
|
||||
<br>
|
||||
<h3>The BUFFER object.</h3>
|
||||
Reading is done through the BUFFER object. here is the public interface :
|
||||
<br>
|
||||
<div class="prot">
|
||||
BUFFER *buffer_new();
|
||||
</div>
|
||||
creates a buffer object.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void *buffer_get(BUFFER *buffer);
|
||||
</div>
|
||||
returns a pointer to the begining of buffer.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int buffer_get_len(BUFFER *buffer);
|
||||
</div>
|
||||
returns buffer's data size.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void buffer_free(BUFFER *buffer);
|
||||
</div>
|
||||
destoys the buffer.
|
||||
<br>
|
||||
<br>
|
||||
How to use the buffer system when you've read something:<br>
|
||||
I've seen people doing such code:<br>
|
||||
<div class="prot">
|
||||
char buffer[256];<br>
|
||||
channel_read(channel,buf,1234,0);<br>
|
||||
strcpy(buffer,buf.data);<br>
|
||||
</div>
|
||||
The correct way of doing this:
|
||||
<div class="prot">
|
||||
char buffer[256];<br>
|
||||
int i;<br>
|
||||
i=channel_read(channel,buf,1234,0);<br>
|
||||
if(i<=0)<br>
|
||||
go_out()...<br>
|
||||
if(i>=256)<br>
|
||||
i=255;<br>
|
||||
memcpy(buffer,buffer_get(buf),i);<br>
|
||||
buffer[i]=0;
|
||||
</div>
|
||||
Do not expect the buffer to be null-terminated. Don't access the internal structure of buffer. Check the sizes before copying.<br>
|
||||
</div>
|
||||
<h2>6- The SFTP subsystem</h2>
|
||||
<div class="tout">
|
||||
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.<br>
|
||||
<br>
|
||||
<h3>A) Opening the session</h3>
|
||||
<div class="prot">
|
||||
SFTP_SESSION *sftp_new(SSH_SESSION *session);
|
||||
int sftp_init(SFTP_SESSION *sftp);
|
||||
</div>
|
||||
The former returns a SFTP_SESSION handle. It returns NULL if things didn't
|
||||
work as expected.<br>
|
||||
sftp_init makes some initialisation work. It returns 0 if things went right.
|
||||
Both of them must be called.<br>
|
||||
<h3>B) Opening and reading a directory</h3>
|
||||
<div class="prot">
|
||||
SFTP_DIR *sftp_opendir(SFTP_SESSION *session, char *path);
|
||||
</div>
|
||||
opens a directory for file listing. Returns NULL in error case.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
|
||||
</div>
|
||||
This function reads one file attribute from an opened directory. It
|
||||
returns NULL if the directory is EOF, or if something wrong happened.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_dir_eof(SFTP_DIR *dir);
|
||||
</div>
|
||||
When a <i>sftp_readdir()</i> returned NULL, you can use this function to
|
||||
tell if an EOF occured. the function returns 0 if no EOF occured.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void sftp_attributes_free(SFTP_ATTRIBUTES *file);
|
||||
</div>
|
||||
You have to free any SFTP_ATTRIBUTE structure given by an other function
|
||||
with it.<br><br>
|
||||
<div class="prot">
|
||||
int sftp_dir_close(SFTP_DIR *dir);
|
||||
</div>
|
||||
closes an opened directory. returns 0 when no error occured.
|
||||
<br><br>
|
||||
<h3>C) Opening, reading, writing files</h3>
|
||||
<div class="prot">
|
||||
SFTP_FILE *sftp_open(SFTP_SESSION *session, char *file, int access,
|
||||
SFTP_ATTRIBUTES *attr);
|
||||
</div>
|
||||
Opens a file. The access flags are the same than the stdio flags.<br>
|
||||
see open(2) for more details.<br>
|
||||
attr are the wanted attributes for the new file. If you supply NULL,
|
||||
default values will be used.<br>
|
||||
rem: more work is going on parsing/making the attributes structure
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_read(SFTP_FILE *file, void *dest, int len);
|
||||
</div>
|
||||
read on a file. Works as the fread() function. It is blocking by default but you can change the default behaviour with <i>sftp_file_set_nonblocking()</i>.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void sftp_file_set_nonblocking(SFTP_FILE *file);
|
||||
</div>
|
||||
sets the file non blocking. reads on this file won't ever block. You can't detect end of files this way.<br>
|
||||
*** TODO more work going there for EOF ****
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void sftp_file_set_blocking(SFTP_FILE *file);
|
||||
</div>
|
||||
restore the default setting of sftp_read.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_write(SFTP_FILE *file, void *source, int len);
|
||||
</div>
|
||||
works as fwrite() function. It is a blocking write.<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
void sftp_seek(SFTP_FILE *file, int new_offset);
|
||||
</div>
|
||||
seek into the file for reading/writing at an other place.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
unsigned long sftp_tell(SFTP_FILE *file);
|
||||
</div>
|
||||
returns the current offset (both writing and reading) into the opened file.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
void sftp_rewind(SFTP_FILE *file);
|
||||
</div>
|
||||
same as sftp_seek(file,0);
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_file_close(SFTP_FILE *file);
|
||||
</div>
|
||||
closes a file handle. returns 0 in no error case.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_rm(SFTP_SESSION *sftp, char *file);
|
||||
</div>
|
||||
deletes a file.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_rmdir(SFTP_SESSION *sftp, char *directory);
|
||||
</div>
|
||||
<br>
|
||||
deletes a directory.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr);
|
||||
</div>
|
||||
makes a directory, with the given attributes. You can't pass NULL for attr and hope it works.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname);
|
||||
</div>
|
||||
changes the name of a file or directory.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr);
|
||||
</div>
|
||||
changes the attributes of a file or directory.
|
||||
<br><br>
|
||||
<div class="prot">
|
||||
char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path);
|
||||
</div>
|
||||
gives the canonicalized form of some path. You have to
|
||||
free the pointer given in return.<br>
|
||||
(returns NULL if error).
|
||||
<br><br>
|
||||
|
||||
(a function to make proper SFTP_ATTRIBUTES structures is on the way )
|
||||
|
||||
<h3>D) Closing the session</h3>
|
||||
<div class="prot">
|
||||
void sftp_free(SFTP_SESSION *sftp);
|
||||
</div>
|
||||
it closes the sftp channel and subsystem.
|
||||
</div>
|
||||
|
||||
<h2>7- Handling the errors</h2>
|
||||
<div class="tout">
|
||||
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.<br>
|
||||
ssh_error_code() returns the error code number. it's declared as an enum:<br>
|
||||
SSH_NO_ERROR, SSH_REQUEST_DENIED, SSH_INVALID_REQUEST, SSH_CONNECTION_LOST,
|
||||
SSH_FATAL, SSH_INVALID_DATA.<br><br>
|
||||
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, ...).<br>
|
||||
SSH_INVALID_REQUEST means the library got some garbage from server. (But might be
|
||||
recoverable).<br>
|
||||
SSH_FATAL means the connection has an important problem and isn't probably
|
||||
recoverable.<br>
|
||||
<br>
|
||||
Most of time, the error returned are SSH_FATAL, but some functions (generaly the
|
||||
<i>ssh_request_*</i> ones) may fail because of server denying request. In these cases, SSH_REQUEST_DENIED is returned.<br><br>
|
||||
|
||||
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.<br>
|
||||
<br>
|
||||
<div class="prot">
|
||||
char *ssh_get_error(SSH_SESSION *session);
|
||||
</div>
|
||||
returns a pointer to a static message error from the given session. No
|
||||
message freeing is needed.<br><br>
|
||||
<div class="prot">
|
||||
enum ssh_error ssh_get_error_code(SSH_SESSION *session);
|
||||
</div>
|
||||
returns the error code that last happened along with the message.
|
||||
<br><br>
|
||||
</div>
|
||||
|
||||
<h2>8- Final word</h2>
|
||||
<div class="tout">
|
||||
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 !
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
107
doc/base64.txt
Normal file
107
doc/base64.txt
Normal file
@@ -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.
|
||||
647
doc/draft-ietf-secsh-agent-01.txt
Normal file
647
doc/draft-ietf-secsh-agent-01.txt
Normal file
@@ -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 <sjl@ssh.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
|
||||
|
||||
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]
|
||||
1736
doc/draft-ietf-secsh-architecture-14.txt
Normal file
1736
doc/draft-ietf-secsh-architecture-14.txt
Normal file
File diff suppressed because it is too large
Load Diff
559
doc/draft-ietf-secsh-assignednumbers-04.txt
Normal file
559
doc/draft-ietf-secsh-assignednumbers-04.txt
Normal file
@@ -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]
|
||||
|
||||
|
||||
366
doc/draft-ietf-secsh-auth-kbdinteract-05-cleaned.txt
Normal file
366
doc/draft-ietf-secsh-auth-kbdinteract-05-cleaned.txt
Normal file
@@ -0,0 +1,366 @@
|
||||
|
||||
Generic Message Exchange Authentication For SSH
|
||||
<draft-ietf-secsh-auth-kbdinteract-05.txt>
|
||||
|
||||
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
|
||||
619
doc/draft-ietf-secsh-auth-kbdinteract-05.txt
Normal file
619
doc/draft-ietf-secsh-auth-kbdinteract-05.txt
Normal file
@@ -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
|
||||
<draft-ietf-secsh-auth-kbdinteract-05.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/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 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]
|
||||
|
||||
394
doc/draft-ietf-secsh-break-00.txt
Normal file
394
doc/draft-ietf-secsh-break-00.txt
Normal file
@@ -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]
|
||||
|
||||
|
||||
1232
doc/draft-ietf-secsh-connect-17.txt
Normal file
1232
doc/draft-ietf-secsh-connect-17.txt
Normal file
File diff suppressed because it is too large
Load Diff
451
doc/draft-ietf-secsh-dh-group-exchange-04.txt
Normal file
451
doc/draft-ietf-secsh-dh-group-exchange-04.txt
Normal file
@@ -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]
|
||||
|
||||
616
doc/draft-ietf-secsh-dns-04.txt
Normal file
616
doc/draft-ietf-secsh-dns-04.txt
Normal file
@@ -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]
|
||||
|
||||
1626
doc/draft-ietf-secsh-filexfer-02.txt
Normal file
1626
doc/draft-ietf-secsh-filexfer-02.txt
Normal file
File diff suppressed because it is too large
Load Diff
1962
doc/draft-ietf-secsh-filexfer-03.txt
Normal file
1962
doc/draft-ietf-secsh-filexfer-03.txt
Normal file
File diff suppressed because it is too large
Load Diff
2130
doc/draft-ietf-secsh-filexfer-04.txt
Normal file
2130
doc/draft-ietf-secsh-filexfer-04.txt
Normal file
File diff suppressed because it is too large
Load Diff
120
doc/draft-ietf-secsh-fingerprint-01.txt
Normal file
120
doc/draft-ietf-secsh-fingerprint-01.txt
Normal file
@@ -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]
|
||||
|
||||
|
||||
1509
doc/draft-ietf-secsh-gsskeyex-06.txt
Normal file
1509
doc/draft-ietf-secsh-gsskeyex-06.txt
Normal file
File diff suppressed because it is too large
Load Diff
619
doc/draft-ietf-secsh-newmodes-00.txt
Normal file
619
doc/draft-ietf-secsh-newmodes-00.txt
Normal file
@@ -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 <cipher>-ctr means that the block cipher <cipher> is to be
|
||||
used in "stateful-decryption counter" (SDCTR) mode. Let L be the
|
||||
block length of <cipher> 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 <X> 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 <X> with <cipher>
|
||||
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 <X> with
|
||||
<cipher> 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]
|
||||
|
||||
506
doc/draft-ietf-secsh-publickeyfile-03.txt
Normal file
506
doc/draft-ietf-secsh-publickeyfile-03.txt
Normal file
@@ -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, <CR>, <LF> or
|
||||
<CR><LF>.
|
||||
|
||||
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]
|
||||
|
||||
|
||||
426
doc/draft-ietf-secsh-scp-sftp-ssh-uri-00.txt
Normal file
426
doc/draft-ietf-secsh-scp-sftp-ssh-uri-00.txt
Normal file
@@ -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]
|
||||
1624
doc/draft-ietf-secsh-transport-16.txt
Normal file
1624
doc/draft-ietf-secsh-transport-16.txt
Normal file
File diff suppressed because it is too large
Load Diff
840
doc/draft-ietf-secsh-userauth-17.txt
Normal file
840
doc/draft-ietf-secsh-userauth-17.txt
Normal file
@@ -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]
|
||||
|
||||
370
doc/libssh-0.2-api-1.txt
Normal file
370
doc/libssh-0.2-api-1.txt
Normal file
@@ -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.
|
||||
|
||||
1501
doc/protocol-1.5.txt
Normal file
1501
doc/protocol-1.5.txt
Normal file
File diff suppressed because it is too large
Load Diff
184
doc/style.css
Normal file
184
doc/style.css
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
1
include/libssh/config.h
Symbolic link
1
include/libssh/config.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../config.h
|
||||
47
include/libssh/crypto.h
Normal file
47
include/libssh/crypto.h
Normal file
@@ -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);
|
||||
};
|
||||
|
||||
234
include/libssh/libssh.h
Normal file
234
include/libssh/libssh.h
Normal file
@@ -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 <libssh/config.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h> /* for fd_set * */
|
||||
#include <sys/types.h>
|
||||
#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 */
|
||||
444
include/libssh/priv.h
Normal file
444
include/libssh/priv.h
Normal file
@@ -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 <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/hmac.h>
|
||||
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 <openssl/bn.h>
|
||||
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 <sys/time.h>
|
||||
#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 */
|
||||
31
include/libssh/server.h
Normal file
31
include/libssh/server.h
Normal file
@@ -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
|
||||
225
include/libssh/sftp.h
Normal file
225
include/libssh/sftp.h
Normal file
@@ -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 <libssh/libssh.h>
|
||||
#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 */
|
||||
82
include/libssh/ssh1.h
Normal file
82
include/libssh/ssh1.h
Normal file
@@ -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
|
||||
|
||||
69
include/libssh/ssh2.h
Normal file
69
include/libssh/ssh2.h
Normal file
@@ -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
|
||||
251
install-sh
Executable file
251
install-sh
Executable file
@@ -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
|
||||
129
libssh.kdevelop
Normal file
129
libssh.kdevelop
Normal file
@@ -0,0 +1,129 @@
|
||||
<?xml version = '1.0'?>
|
||||
<kdevelop>
|
||||
<general>
|
||||
<author>Aris Adamantiadis (aka spacewalker)</author>
|
||||
<email>aris@0xbadc0de.be</email>
|
||||
<version>$VERSION$</version>
|
||||
<projectmanagement>KDevAutoProject</projectmanagement>
|
||||
<primarylanguage>C</primarylanguage>
|
||||
<ignoreparts/>
|
||||
</general>
|
||||
<kdevautoproject>
|
||||
<general>
|
||||
<activetarget>src/libssh</activetarget>
|
||||
<useconfiguration>debug</useconfiguration>
|
||||
</general>
|
||||
<run>
|
||||
<mainprogram>src/libssh</mainprogram>
|
||||
<directoryradio>executable</directoryradio>
|
||||
</run>
|
||||
<configurations>
|
||||
<optimized>
|
||||
<builddir>optimized</builddir>
|
||||
<ccompiler>GccOptions</ccompiler>
|
||||
<cxxcompiler>GppOptions</cxxcompiler>
|
||||
<f77compiler>G77Options</f77compiler>
|
||||
<cflags>-O2 -g0</cflags>
|
||||
</optimized>
|
||||
<debug>
|
||||
<configargs>--enable-debug=full</configargs>
|
||||
<builddir>debug</builddir>
|
||||
<ccompiler>GccOptions</ccompiler>
|
||||
<cxxcompiler>GppOptions</cxxcompiler>
|
||||
<f77compiler>G77Options</f77compiler>
|
||||
<cflags>-O0 -g3</cflags>
|
||||
</debug>
|
||||
</configurations>
|
||||
<make>
|
||||
<envvars>
|
||||
<envvar value="1" name="WANT_AUTOCONF_2_5" />
|
||||
<envvar value="1" name="WANT_AUTOMAKE_1_6" />
|
||||
</envvars>
|
||||
</make>
|
||||
</kdevautoproject>
|
||||
<kdevdebugger>
|
||||
<general>
|
||||
<dbgshell>libtool</dbgshell>
|
||||
</general>
|
||||
</kdevdebugger>
|
||||
<kdevdoctreeview>
|
||||
<ignoretocs>
|
||||
<toc>ada</toc>
|
||||
<toc>ada_bugs_gcc</toc>
|
||||
<toc>bash</toc>
|
||||
<toc>bash_bugs</toc>
|
||||
<toc>clanlib</toc>
|
||||
<toc>fortran_bugs_gcc</toc>
|
||||
<toc>gnome1</toc>
|
||||
<toc>gnustep</toc>
|
||||
<toc>gtk</toc>
|
||||
<toc>gtk_bugs</toc>
|
||||
<toc>haskell</toc>
|
||||
<toc>haskell_bugs_ghc</toc>
|
||||
<toc>java_bugs_gcc</toc>
|
||||
<toc>java_bugs_sun</toc>
|
||||
<toc>kde2book</toc>
|
||||
<toc>libstdc++</toc>
|
||||
<toc>opengl</toc>
|
||||
<toc>pascal_bugs_fp</toc>
|
||||
<toc>php</toc>
|
||||
<toc>php_bugs</toc>
|
||||
<toc>perl</toc>
|
||||
<toc>perl_bugs</toc>
|
||||
<toc>python</toc>
|
||||
<toc>python_bugs</toc>
|
||||
<toc>qt-kdev3</toc>
|
||||
<toc>ruby</toc>
|
||||
<toc>ruby_bugs</toc>
|
||||
<toc>sdl</toc>
|
||||
<toc>stl</toc>
|
||||
<toc>sw</toc>
|
||||
<toc>w3c-dom-level2-html</toc>
|
||||
<toc>w3c-svg</toc>
|
||||
<toc>w3c-uaag10</toc>
|
||||
<toc>wxwidgets_bugs</toc>
|
||||
</ignoretocs>
|
||||
<ignoreqt_xml>
|
||||
<toc>Guide to the Qt Translation Tools</toc>
|
||||
<toc>Qt Assistant Manual</toc>
|
||||
<toc>Qt Designer Manual</toc>
|
||||
<toc>Qt Reference Documentation</toc>
|
||||
<toc>qmake User Guide</toc>
|
||||
</ignoreqt_xml>
|
||||
<ignoredoxygen>
|
||||
<toc>KDE Libraries (Doxygen)</toc>
|
||||
</ignoredoxygen>
|
||||
</kdevdoctreeview>
|
||||
<kdevfilecreate>
|
||||
<filetypes/>
|
||||
<useglobaltypes>
|
||||
<type ext="c" />
|
||||
<type ext="h" />
|
||||
</useglobaltypes>
|
||||
</kdevfilecreate>
|
||||
<kdevcppsupport>
|
||||
<references/>
|
||||
<codecompletion>
|
||||
<includeGlobalFunctions>true</includeGlobalFunctions>
|
||||
<includeTypes>true</includeTypes>
|
||||
<includeEnums>true</includeEnums>
|
||||
<includeTypedefs>false</includeTypedefs>
|
||||
<automaticCodeCompletion>true</automaticCodeCompletion>
|
||||
<automaticArgumentsHint>true</automaticArgumentsHint>
|
||||
<automaticHeaderCompletion>true</automaticHeaderCompletion>
|
||||
<codeCompletionDelay>250</codeCompletionDelay>
|
||||
<argumentsHintDelay>400</argumentsHintDelay>
|
||||
<headerCompletionDelay>250</headerCompletionDelay>
|
||||
</codecompletion>
|
||||
</kdevcppsupport>
|
||||
<kdevfileview>
|
||||
<groups>
|
||||
<hidenonprojectfiles>false</hidenonprojectfiles>
|
||||
<hidenonlocation>false</hidenonlocation>
|
||||
</groups>
|
||||
<tree>
|
||||
<hidepatterns>*.o,*.lo,CVS</hidepatterns>
|
||||
<hidenonprojectfiles>false</hidenonprojectfiles>
|
||||
</tree>
|
||||
</kdevfileview>
|
||||
</kdevelop>
|
||||
BIN
libssh.kdevelop.pcs
Normal file
BIN
libssh.kdevelop.pcs
Normal file
Binary file not shown.
29
libssh.kdevses
Normal file
29
libssh.kdevses
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version = '1.0' encoding = 'UTF-8'?>
|
||||
<!DOCTYPE KDevPrjSession>
|
||||
<KDevPrjSession>
|
||||
<DocsAndViews NumberOfDocuments="2" >
|
||||
<Doc0 NumberOfViews="1" URL="file:/home/aris/dev/libssh-dev/include/libssh/libssh.h" >
|
||||
<View0 Type="Source" />
|
||||
</Doc0>
|
||||
<Doc1 NumberOfViews="1" URL="file:/home/aris/dev/libssh-dev/libssh/auth.c" >
|
||||
<View0 line="0" Type="Source" />
|
||||
</Doc1>
|
||||
</DocsAndViews>
|
||||
<pluginList>
|
||||
<kdevbookmarks>
|
||||
<bookmarks/>
|
||||
</kdevbookmarks>
|
||||
<kdevsubversion>
|
||||
<subversion recurseresolve="1" recurserelocate="1" recursemerge="1" recursecommit="1" base="" recursepropget="1" recurseswitch="1" recurseupdate="1" recursepropset="1" recursediff="1" recurserevert="1" forcemove="1" recursecheckout="1" forceremove="1" recurseadd="1" recurseproplist="1" forcemerge="1" />
|
||||
</kdevsubversion>
|
||||
<kdevvalgrind>
|
||||
<executable path="" params="" />
|
||||
<valgrind path="" params="" />
|
||||
<calltree path="" params="" />
|
||||
<kcachegrind path="" />
|
||||
</kdevvalgrind>
|
||||
<kdevdebugger>
|
||||
<breakpointList/>
|
||||
</kdevdebugger>
|
||||
</pluginList>
|
||||
</KDevPrjSession>
|
||||
44
libssh/Makefile.in
Normal file
44
libssh/Makefile.in
Normal file
@@ -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
|
||||
|
||||
605
libssh/auth.c
Normal file
605
libssh/auth.c
Normal file
@@ -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 <string.h>
|
||||
#include <netdb.h>
|
||||
|
||||
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;i<n;++i){
|
||||
burn(kbd->prompts[i]);
|
||||
free(kbd->prompts[i]);
|
||||
}
|
||||
free(kbd->prompts);
|
||||
}
|
||||
if(kbd->answers){
|
||||
for(i=0;i<n;++i){
|
||||
burn(kbd->answers[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;i<n;++i){
|
||||
burn(kbd->prompts[i]);
|
||||
free(kbd->prompts[i]);
|
||||
}
|
||||
free(kbd->prompts);
|
||||
kbd->prompts=NULL;
|
||||
}
|
||||
if(kbd->answers){
|
||||
for(i=0;i<n;++i){
|
||||
burn(kbd->answers[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;i<nprompts;++i){
|
||||
tmp=buffer_get_ssh_string(session->in_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;i<session->kbdint->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);
|
||||
}
|
||||
210
libssh/base64.c
Normal file
210
libssh/base64.c
Normal file
@@ -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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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<<n)-1)
|
||||
static void _bin_to_base64(unsigned char *dest, unsigned char source[3], int len){
|
||||
switch (len){
|
||||
case 1:
|
||||
dest[0]=alphabet[(source[0]>>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;
|
||||
}
|
||||
181
libssh/buffer.c
Normal file
181
libssh/buffer.c
Normal file
@@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
701
libssh/channels.c
Normal file
701
libssh/channels.c
Normal file
@@ -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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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_window<len){
|
||||
ssh_say(2,"Remote window is %d bytes. going to write %d bytes\n",
|
||||
channel->remote_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;
|
||||
}
|
||||
|
||||
287
libssh/client.c
Normal file
287
libssh/client.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#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" ;
|
||||
}
|
||||
286
libssh/connect.c
Normal file
286
libssh/connect.c
Normal file
@@ -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 <netdb.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include "libssh/priv.h"
|
||||
#ifdef HAVE_SYS_POLL_H
|
||||
#include <sys/poll.h>
|
||||
#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;(i<maxfd) && !set;i++)
|
||||
if(FD_ISSET(i,&localset))
|
||||
set=1;
|
||||
// j!=0 means a channel has data
|
||||
if( (j!=0) || (set!=0)){
|
||||
if(maxfd>0)
|
||||
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;i<maxfd;i++)
|
||||
if(FD_ISSET(i,readfds) && FD_ISSET(i,&localset))
|
||||
FD_SET(i,&localset2);
|
||||
memcpy(readfds,&localset2,sizeof(fd_set));
|
||||
return 0;
|
||||
}
|
||||
88
libssh/crc32.c
Normal file
88
libssh/crc32.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/* simple CRC32 code */
|
||||
/*
|
||||
* 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"
|
||||
static u32 crc_table[] = {
|
||||
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
|
||||
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
|
||||
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
|
||||
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
|
||||
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
|
||||
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
|
||||
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
|
||||
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
|
||||
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
|
||||
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
|
||||
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
|
||||
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
|
||||
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
|
||||
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
|
||||
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
|
||||
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
|
||||
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
|
||||
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
|
||||
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
|
||||
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
|
||||
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
|
||||
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
|
||||
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
|
||||
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
|
||||
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
|
||||
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
|
||||
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
|
||||
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
|
||||
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
|
||||
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
|
||||
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
|
||||
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
|
||||
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
|
||||
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
|
||||
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
|
||||
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
|
||||
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
|
||||
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
|
||||
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
|
||||
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
|
||||
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
|
||||
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
|
||||
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
|
||||
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
|
||||
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
|
||||
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
|
||||
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
|
||||
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
|
||||
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
|
||||
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
|
||||
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
|
||||
0x2d02ef8dUL
|
||||
};
|
||||
|
||||
u32 ssh_crc32(char *buf, int len) {
|
||||
u32 ret=0;
|
||||
while(len>0){
|
||||
ret=crc_table[(ret ^ *buf) & 0xff] ^ (ret >> 8);
|
||||
--len;
|
||||
++buf;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
105
libssh/crypt.c
Normal file
105
libssh/crypt.c
Normal file
@@ -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 <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#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);
|
||||
}
|
||||
412
libssh/dh.c
Normal file
412
libssh/dh.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string.h>
|
||||
#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;i<len-1;i++)
|
||||
printf("%.2hhx:",what[i]);
|
||||
printf("%.2hhx\n",what[i]);
|
||||
}
|
||||
|
||||
void dh_generate_x(SSH_SESSION *session){
|
||||
session->next_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;
|
||||
}
|
||||
56
libssh/error.c
Normal file
56
libssh/error.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#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;
|
||||
}
|
||||
140
libssh/gzip.c
Normal file
140
libssh/gzip.c
Normal file
@@ -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 <zlib.h>
|
||||
#include <string.h>
|
||||
#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 */
|
||||
439
libssh/kex.c
Normal file
439
libssh/kex.c
Normal file
@@ -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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#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;i<n;i++){
|
||||
tokens[i]=ptr;
|
||||
while(*ptr)
|
||||
ptr++; // find a zero
|
||||
ptr++; // then go one step further
|
||||
}
|
||||
tokens[i]=NULL;
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/* same as tokenize(), but with spaces instead of ',' */
|
||||
char **space_tokenize(char *chain){
|
||||
char **tokens;
|
||||
int n=1;
|
||||
int i=0;
|
||||
char *ptr=chain=strdup(chain);
|
||||
while(*ptr==' ')
|
||||
++ptr; /* skip initial spaces */
|
||||
while(*ptr){
|
||||
if(*ptr==' '){
|
||||
n++; /* count one token per word */
|
||||
*ptr=0;
|
||||
while(*(ptr+1)==' '){ /* don't count if the tokens have more than 2 spaces */
|
||||
*(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; /* we don't pass the initial spaces because the "chain" pointer is needed by the caller */
|
||||
/* function to free the tokens. */
|
||||
for(i=0;i<n;i++){
|
||||
tokens[i]=ptr;
|
||||
if(i!=n-1){
|
||||
while(*ptr)
|
||||
ptr++; // find a zero
|
||||
while(!*(ptr+1))
|
||||
++ptr; /* if the zero is followed by other zeros, go through them */
|
||||
ptr++; // then go one step further
|
||||
}
|
||||
}
|
||||
tokens[i]=NULL;
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/* find_matching gets 2 parameters : a list of available objects (in_d), separated by colons,*/
|
||||
/* and a list of prefered objects (what_d) */
|
||||
/* it will return a strduped pointer on the first prefered object found in the available objects list */
|
||||
|
||||
static char *find_matching(char *in_d, char *what_d){
|
||||
char ** tok_in, **tok_what;
|
||||
int i_in, i_what;
|
||||
char *ret;
|
||||
|
||||
if( ! (in_d && what_d))
|
||||
return NULL; /* don't deal with null args */
|
||||
ssh_say(3,"find_matching(\"%s\",\"%s\") = ",in_d,what_d);
|
||||
tok_in=tokenize(in_d);
|
||||
tok_what=tokenize(what_d);
|
||||
for(i_in=0; tok_in[i_in]; ++i_in){
|
||||
for(i_what=0; tok_what[i_what] ; ++i_what){
|
||||
if(!strcmp(tok_in[i_in],tok_what[i_what])){
|
||||
/* match */
|
||||
ssh_say(3,"\"%s\"\n",tok_in[i_in]);
|
||||
ret=strdup(tok_in[i_in]);
|
||||
/* free the tokens */
|
||||
free(tok_in[0]);
|
||||
free(tok_what[0]);
|
||||
free(tok_in);
|
||||
free(tok_what);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
ssh_say(3,"NULL\n");
|
||||
free(tok_in[0]);
|
||||
free(tok_what[0]);
|
||||
free(tok_in);
|
||||
free(tok_what);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ssh_get_kex(SSH_SESSION *session,int server_kex ){
|
||||
STRING *str;
|
||||
char *strings[10];
|
||||
int i;
|
||||
if(packet_wait(session,SSH2_MSG_KEXINIT,1))
|
||||
return -1;
|
||||
if(buffer_get_data(session->in_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<<SSH_CIPHER_3DES))){
|
||||
ssh_set_error(NULL,SSH_FATAL,"Remote server doesn't accept 3des");
|
||||
return -1;
|
||||
}
|
||||
packet_clear_out(session);
|
||||
buffer_add_u8(session->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;
|
||||
|
||||
}
|
||||
|
||||
344
libssh/keyfiles.c
Normal file
344
libssh/keyfiles.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#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;
|
||||
}
|
||||
370
libssh/keys.c
Normal file
370
libssh/keys.c
Normal file
@@ -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 <string.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#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(len<rsalen)
|
||||
ssh_say(0,"Len %d < %d\n",len,rsalen);
|
||||
sign->type=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;
|
||||
}
|
||||
|
||||
98
libssh/misc.c
Normal file
98
libssh/misc.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#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
|
||||
}
|
||||
382
libssh/options.c
Normal file
382
libssh/options.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#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<current;i++)
|
||||
argv[i+1]=save[i]; // don't erase argv[0]
|
||||
argv[current+1]=NULL;
|
||||
*argcptr=current+1;
|
||||
free(save);
|
||||
/* set a new option struct */
|
||||
if(compress){
|
||||
if(ssh_options_set_wanted_algos(options,SSH_COMP_C_S,"zlib"))
|
||||
cont=0;
|
||||
if(ssh_options_set_wanted_algos(options,SSH_COMP_S_C,"zlib"))
|
||||
cont=0;
|
||||
}
|
||||
if(cont &&cipher){
|
||||
if(ssh_options_set_wanted_algos(options,SSH_CRYPT_C_S,cipher))
|
||||
cont=0;
|
||||
if(cont && ssh_options_set_wanted_algos(options,SSH_CRYPT_S_C,cipher))
|
||||
cont=0;
|
||||
}
|
||||
if(cont && usersa)
|
||||
if(ssh_options_set_wanted_algos(options,SSH_HOSTKEYS,"ssh-rsa"))
|
||||
cont=0;
|
||||
if(cont && usedss)
|
||||
if(ssh_options_set_wanted_algos(options,SSH_HOSTKEYS,"ssh-dss"))
|
||||
cont=0;
|
||||
if(cont && user)
|
||||
ssh_options_set_username(options,user);
|
||||
if(cont && identity)
|
||||
ssh_options_set_identity(options,identity);
|
||||
if(cont && localaddr)
|
||||
ssh_options_set_bind(options,localaddr,0);
|
||||
ssh_options_set_port(options,port);
|
||||
if(ssh1){
|
||||
ssh_options_allow_ssh1(options,1);
|
||||
ssh_options_allow_ssh2(options,0);
|
||||
} else { // default behaviour
|
||||
ssh_options_allow_ssh1(options,0);
|
||||
ssh_options_allow_ssh2(options,1);
|
||||
}
|
||||
|
||||
if(!cont){
|
||||
return -1;
|
||||
} else
|
||||
return 0 ;
|
||||
}
|
||||
563
libssh/packet.c
Normal file
563
libssh/packet.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/* packet.c */
|
||||
/* packet building functions */
|
||||
/*
|
||||
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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#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();
|
||||
}
|
||||
|
||||
128
libssh/server.c
Normal file
128
libssh/server.c
Normal file
@@ -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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#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 */
|
||||
124
libssh/session.c
Normal file
124
libssh/session.c
Normal file
@@ -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 <string.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
1290
libssh/sftp.c
Normal file
1290
libssh/sftp.c
Normal file
File diff suppressed because it is too large
Load Diff
70
libssh/string.c
Normal file
70
libssh/string.c
Normal file
@@ -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 <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#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));
|
||||
}
|
||||
|
||||
329
libssh/wrapper.c
Normal file
329
libssh/wrapper.c
Normal file
@@ -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 <string.h>
|
||||
#ifdef OPENSSL_CRYPTO
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#ifdef HAVE_OPENSSL_AES_H
|
||||
#define HAS_AES
|
||||
#include <openssl/aes.h>
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_BLOWFISH_H
|
||||
#define HAS_BLOWFISH
|
||||
#include <openssl/blowfish.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/des.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
40
mkinstalldirs
Executable file
40
mkinstalldirs
Executable file
@@ -0,0 +1,40 @@
|
||||
#! /bin/sh
|
||||
# mkinstalldirs --- make directory hierarchy
|
||||
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
|
||||
# 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
|
||||
434
sample.c
Normal file
434
sample.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <pty.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#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] && (n<MAXCMD);n++);
|
||||
if(n==MAXCMD)
|
||||
return;
|
||||
cmds[n]=strdup(cmd);
|
||||
}
|
||||
|
||||
void usage(){
|
||||
fprintf(stderr,"Usage : ssh [options] [login@]hostname\n"
|
||||
"Options :\n"
|
||||
" -l user : log in as user\n"
|
||||
" -p port : connect to port\n"
|
||||
" -d : use DSS to verify host public key\n"
|
||||
" -r : use RSA to verify host public key\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int opts(int argc, char **argv){
|
||||
int i;
|
||||
if(strstr(argv[0],"sftp"))
|
||||
sftp=1;
|
||||
// for(i=0;i<argc;i++)
|
||||
// printf("%d : %s\n",i,argv[i]);
|
||||
/* insert your own arguments here */
|
||||
while((i=getopt(argc,argv,""))!=-1){
|
||||
switch(i){
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if(optind < argc)
|
||||
host=argv[optind++];
|
||||
while(optind < argc)
|
||||
add_cmd(argv[optind++]);
|
||||
if(host==NULL)
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void do_cleanup(){
|
||||
tcsetattr(0,TCSANOW,&terminal);
|
||||
}
|
||||
void do_exit(){
|
||||
do_cleanup();
|
||||
exit(0);
|
||||
}
|
||||
CHANNEL *chan;
|
||||
int signal_delayed=0;
|
||||
void setsignal();
|
||||
void sigwindowchanged(){
|
||||
signal_delayed=1;
|
||||
}
|
||||
void sizechanged(){
|
||||
struct winsize win = { 0, 0, 0, 0 };
|
||||
ioctl(1, TIOCGWINSZ, &win);
|
||||
channel_change_pty_size(chan,win.ws_col, win.ws_row);
|
||||
// printf("Changed pty size\n");
|
||||
setsignal();
|
||||
}
|
||||
void setsignal(){
|
||||
signal(SIGWINCH,sigwindowchanged);
|
||||
signal_delayed=0;
|
||||
}
|
||||
|
||||
void select_loop(SSH_SESSION *session,CHANNEL *channel){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[10];
|
||||
BUFFER *readbuf=buffer_new();
|
||||
CHANNEL *channels[]={channel,NULL};
|
||||
CHANNEL *outchannel[2];
|
||||
int lus;
|
||||
int eof=0;
|
||||
int ret;
|
||||
while(channel){
|
||||
/* when a signal is caught, ssh_select will return
|
||||
* with SSH_EINTR, which means it should be started
|
||||
* again. It lets you handle the signal the faster you
|
||||
* can, like in this window changed example. Of course, if
|
||||
* your signal handler doesn't call libssh at all, you're
|
||||
* free to handle signals directly in sighandler.
|
||||
*/
|
||||
do{
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
timeout.tv_sec=30;
|
||||
timeout.tv_usec=0;
|
||||
ret=ssh_select(channels,outchannel,0+1,&fds,&timeout);
|
||||
if(signal_delayed)
|
||||
sizechanged();
|
||||
} while (ret==SSH_EINTR);
|
||||
if(FD_ISSET(0,&fds)){
|
||||
lus=read(0,buffer,10);
|
||||
if(lus){
|
||||
channel_write(channel,buffer,lus);
|
||||
}
|
||||
else{
|
||||
eof=1;
|
||||
channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if(outchannel[0]){
|
||||
while(channel_poll(outchannel[0],0)){
|
||||
lus=channel_read(outchannel[0],readbuf,0,0);
|
||||
if(lus==-1){
|
||||
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_say(1,"EOF received\n");
|
||||
} else
|
||||
write(1,buffer_get(readbuf),lus);
|
||||
}
|
||||
while(channel_poll(outchannel[0],1)){ /* stderr */
|
||||
lus=channel_read(outchannel[0],readbuf,0,1);
|
||||
if(lus==-1){
|
||||
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_say(1,"EOF received\n");
|
||||
} else
|
||||
write(2,buffer_get(readbuf),lus);
|
||||
}
|
||||
}
|
||||
if(!channel_is_open(channel)){
|
||||
channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
}
|
||||
buffer_free(readbuf);
|
||||
}
|
||||
|
||||
void shell(SSH_SESSION *session){
|
||||
CHANNEL *channel;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
if(interactive){
|
||||
tcgetattr(0,&terminal_local);
|
||||
memcpy(&terminal,&terminal_local,sizeof(struct termios));
|
||||
cfmakeraw(&terminal_local);
|
||||
tcsetattr(0,TCSANOW,&terminal_local);
|
||||
setsignal();
|
||||
}
|
||||
signal(SIGTERM,do_cleanup);
|
||||
channel = channel_new(session);
|
||||
channel_open_session(channel);
|
||||
chan=channel;
|
||||
if(interactive){
|
||||
channel_request_pty(channel);
|
||||
sizechanged();
|
||||
}
|
||||
channel_request_shell(channel);
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
void batch_shell(SSH_SESSION *session){
|
||||
CHANNEL *channel;
|
||||
char buffer[1024];
|
||||
int i,s=0;
|
||||
for(i=0;i<MAXCMD && cmds[i];++i)
|
||||
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
|
||||
channel=channel_new(session);
|
||||
channel_open_session(channel);
|
||||
if(channel_request_exec(channel,buffer)){
|
||||
printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
/* it's just a proof of concept code for sftp, till i write a real documentation about it */
|
||||
void do_sftp(SSH_SESSION *session){
|
||||
SFTP_SESSION *sftp=sftp_new(session);
|
||||
SFTP_DIR *dir;
|
||||
SFTP_ATTRIBUTES *file;
|
||||
SFTP_FILE *fichier;
|
||||
SFTP_FILE *to;
|
||||
int len=1;
|
||||
int i;
|
||||
char data[8000];
|
||||
if(!sftp){
|
||||
ssh_say(0,"sftp error initialising channel : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(sftp_init(sftp)){
|
||||
ssh_say(0,"error initialising sftp : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
/* the connection is made */
|
||||
/* opening a directory */
|
||||
dir=sftp_opendir(sftp,"./");
|
||||
if(!dir) {
|
||||
ssh_say(0,"Directory not opened(%s)\n",ssh_get_error(session));
|
||||
return ;
|
||||
}
|
||||
/* reading the whole directory, file by file */
|
||||
while((file=sftp_readdir(sftp,dir))){
|
||||
ssh_say(0,"%30s(%.8lo) : %.5d.%.5d : %.10lld bytes\n",file->name,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<72>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<69>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<n;++i){
|
||||
prompt=ssh_userauth_kbdint_getprompt(session,i,&echo);
|
||||
if(echo){
|
||||
printf("%s",prompt);
|
||||
fgets(buffer,sizeof(buffer),stdin);
|
||||
buffer[sizeof(buffer)-1]=0;
|
||||
if((ptr=strchr(buffer,'\n')))
|
||||
*ptr=0;
|
||||
ssh_userauth_kbdint_setanswer(session,i,buffer);
|
||||
memset(buffer,0,strlen(buffer));
|
||||
} else {
|
||||
ptr=getpass(prompt);
|
||||
ssh_userauth_kbdint_setanswer(session,i,ptr);
|
||||
}
|
||||
}
|
||||
err=ssh_userauth_kbdint(session,NULL,NULL);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
SSH_SESSION *session;
|
||||
SSH_OPTIONS *options;
|
||||
int auth=0;
|
||||
char *password;
|
||||
char *banner;
|
||||
int state;
|
||||
char buf[10];
|
||||
char hash[MD5_DIGEST_LEN];
|
||||
|
||||
options=ssh_options_new();
|
||||
if(ssh_options_getopt(options,&argc, argv))
|
||||
usage();
|
||||
opts(argc,argv);
|
||||
signal(SIGTERM,do_exit);
|
||||
if(user)
|
||||
ssh_options_set_username(options,user);
|
||||
ssh_options_set_host(options,host);
|
||||
session=ssh_new();
|
||||
ssh_set_options(session,options);
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
state=ssh_is_server_known(session);
|
||||
switch(state){
|
||||
case SSH_SERVER_KNOWN_OK:
|
||||
break; /* ok */
|
||||
case SSH_SERVER_KNOWN_CHANGED:
|
||||
fprintf(stderr,"Host key for server changed : server's one is now :\n");
|
||||
ssh_get_pubkey_hash(session,hash);
|
||||
ssh_print_hexa("Public key hash",hash,MD5_DIGEST_LEN);
|
||||
fprintf(stderr,"For security reason, connection will be stopped\n");
|
||||
ssh_disconnect(session);
|
||||
exit(-1);
|
||||
case SSH_SERVER_FOUND_OTHER:
|
||||
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
|
||||
fprintf(stderr,"An attacker might change the default server key to confuse your client"
|
||||
"into thinking the key does not exist\n"
|
||||
"We advise you to rerun the client with -d or -r for more safety.\n");
|
||||
ssh_disconnect(session);
|
||||
exit(-1);
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
|
||||
ssh_get_pubkey_hash(session,hash);
|
||||
ssh_print_hexa("Public key hash",hash,MD5_DIGEST_LEN);
|
||||
fgets(buf,sizeof(buf),stdin);
|
||||
if(strncasecmp(buf,"yes",3)!=0){
|
||||
ssh_disconnect(session);
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
|
||||
fgets(buf,sizeof(buf),stdin);
|
||||
if(strncasecmp(buf,"yes",3)==0){
|
||||
if(ssh_write_knownhost(session))
|
||||
fprintf(stderr,"error %s\n",ssh_get_error(session));
|
||||
}
|
||||
|
||||
break;
|
||||
case SSH_SERVER_ERROR:
|
||||
fprintf(stderr,"%s",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* no ? you should :) */
|
||||
auth=ssh_userauth_autopubkey(session);
|
||||
if(auth==SSH_AUTH_ERROR){
|
||||
fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
banner=ssh_get_issue_banner(session);
|
||||
if(banner){
|
||||
printf("%s\n",banner);
|
||||
free(banner);
|
||||
}
|
||||
if(auth!=SSH_AUTH_SUCCESS){
|
||||
auth=auth_kbdint(session);
|
||||
if(auth==SSH_AUTH_ERROR){
|
||||
fprintf(stderr,"authenticating with keyb-interactive: %s\n",
|
||||
ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(auth!=SSH_AUTH_SUCCESS){
|
||||
password=getpass("Password : ");
|
||||
if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS){
|
||||
fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return -1;
|
||||
}
|
||||
memset(password,0,strlen(password));
|
||||
}
|
||||
ssh_say(1,"Authentication success\n");
|
||||
if(!sftp){
|
||||
if(!cmds[0])
|
||||
shell(session);
|
||||
else
|
||||
batch_shell(session);
|
||||
}
|
||||
else
|
||||
do_sftp(session);
|
||||
if(!sftp && !cmds[0])
|
||||
do_cleanup();
|
||||
ssh_disconnect(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
samplesftp
Symbolic link
1
samplesftp
Symbolic link
@@ -0,0 +1 @@
|
||||
samplessh
|
||||
BIN
samplesshd
Executable file
BIN
samplesshd
Executable file
Binary file not shown.
50
samplesshd.c
Normal file
50
samplesshd.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/* sshd.c */
|
||||
/* yet another ssh daemon (Yawn!) */
|
||||
/*
|
||||
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. */
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
#include <unistd.h>
|
||||
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;
|
||||
}
|
||||
202
ssh1/auth1.c
Normal file
202
ssh1/auth1.c
Normal file
@@ -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 <string.h>
|
||||
#include <netdb.h>
|
||||
|
||||
/*
|
||||
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 */
|
||||
244
ssh1/channels1.c
Normal file
244
ssh1/channels1.c
Normal file
@@ -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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
||||
Reference in New Issue
Block a user