first import
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@1 7dcaeef0-15fb-0310-b436-a5af3365683c
Этот коммит содержится в:
Коммит
c65f56aefa
5
AUTHORS
Обычный файл
5
AUTHORS
Обычный файл
@ -0,0 +1,5 @@
|
||||
Author(s):
|
||||
Aris Adamantiadis (aka spacewalker) <aris@0xbadc0de.be>
|
||||
|
||||
Contributor(s):
|
||||
Nick Zitzmann <seiryu (at) comcast (dot) net>
|
80
CHANGELOG
Обычный файл
80
CHANGELOG
Обычный файл
@ -0,0 +1,80 @@
|
||||
libssh-0.11-dev
|
||||
-server implementation development. I won't document it before it even works.
|
||||
-small bug corrected when connecting to sun ssh servers.
|
||||
-channel wierdness corrected (writing huge data packets)
|
||||
-channel_read_nonblocking added
|
||||
-channel bug where stderr wasn't correctly read fixed.
|
||||
-sftp_file_set_nonblocking added. It's now possible to have nonblocking SFTP IO
|
||||
-connect_status callback.
|
||||
-priv.h contains the internal functions, libssh.h the public interface
|
||||
-options_set_timeout (thx marcelo) really working.
|
||||
-tcp tunneling through channel_open_forward.
|
||||
-channel_request_exec()
|
||||
-channel_request_env()
|
||||
-ssh_get_pubkey_hash()
|
||||
-ssh_is_server_known()
|
||||
-ssh_write_known_host()
|
||||
-options_set_ssh_dir
|
||||
-how could this happen ! there weren't any channel_close !
|
||||
-nasty channel_free bug resolved.
|
||||
-removed the unsigned long all around the code. use only u8,u32 & u64.
|
||||
-it now compiles and runs under amd64 !
|
||||
-channel_request_pty_size
|
||||
-channel_change_pty_size
|
||||
-options_copy()
|
||||
-ported the doc to an HTML file.
|
||||
-small bugfix in packet.c
|
||||
-prefixed error constants with SSH_
|
||||
-sftp_stat, sftp_lstat, sftp_fstat. thanks Michel Bardiaux for the patch.
|
||||
-again channel number mismatch fixed.
|
||||
-fixed a bug in ssh_select making the select fail when a signal has been caught.
|
||||
-keyboard-interactive authentication working.
|
||||
|
||||
5th march 2004 : libssh-0.1
|
||||
-Begining of sftp subsystem implementation. It's stable enough to be used :)
|
||||
-some cleanup into channels implementation
|
||||
-Now every channel functions is called by its CHANNEL handler. no any way to play again with numbers.
|
||||
-added channel_poll() and channel_read(). Now, it's possible to manipulate channel streams only with channel_read() and channel_write(),
|
||||
with help of channel_poll().
|
||||
-changed the client so it uses the new channel_poll and channel_read interface
|
||||
-small use-after-free bug with channels resolved, and a noninitialised data of SIGNATURE struct.
|
||||
-changed stupidities in lot of function names.
|
||||
-removed a debug output file opened by default.
|
||||
-Added API.txt, the libssh programmer handbook. (I hate documentation)
|
||||
-Various bug fixes from Nick Zitzmann. Thank to him, libssh now runs under macosX !
|
||||
-Developed a cryptographic structure for handling protocols. Adding a custom-based cipher should be the story of thirty
|
||||
minutes. It now supports aes-256,aes-192,aes-128 and blowfish-128 !
|
||||
-An autoconf script which took me half of a day to set up. Respect it!
|
||||
-A ssh_select wrapper has been written.
|
||||
It all means the API has changed. not a lot but enough to be incompatible with anything which has been written.
|
||||
|
||||
10th october 2003 : libssh-0.0.4
|
||||
-some terminal code (eof handling) added
|
||||
-channels bugfix (it still needs some tweaking though)
|
||||
-zlib support
|
||||
-added a wrapper.c file. The goal is to provide a similar API to every cryptographic functions. bignums and sha/md5 are wrapped now.
|
||||
-more work than it first looks.
|
||||
-Support for other crypto libs planed (lighter libs)
|
||||
-Fixed stupid select() bug.
|
||||
-libssh now compiles and links with openssl 0.9.6 (but you're advised to upgrade)
|
||||
-RSA pubkey authentication code now works !
|
||||
|
||||
15th september 2003 : libssh-0.0.3
|
||||
-added install target in makefile
|
||||
-some cleanup in headers files and source code
|
||||
-change default banner and project name to libssh.
|
||||
-new file auth.c to support more and more authentication ways
|
||||
-bugfix(read offbyone) in send_kex
|
||||
-a base64 parser. don't read the source, it's awful. pure 0xbadc0de.
|
||||
-changed the client filename to "ssh". logic isn't it ?
|
||||
-dss publickey authentication ! still need to wait for the rsa one
|
||||
-bugfix in packet.c : now packet are completely read (and read blocks if waiting the packet)
|
||||
-new misc.c contains misc functions
|
||||
|
||||
3rd september 2003: libssh-0.0.2
|
||||
initial release.
|
||||
-client supports both ssh and dss hostkey verification, but doesn't compare
|
||||
them to openssh's files. (~/.ssh/known_hosts)
|
||||
-the only supported authentication method is password.
|
||||
-compiles on linux and openbsd. freebsd and netbsd should work, too
|
||||
-Lot of work which hasn't been discussed here.
|
504
COPYING
Обычный файл
504
COPYING
Обычный файл
@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<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
Обычный файл
266
Doxyfile
Обычный файл
@ -0,0 +1,266 @@
|
||||
# Doxyfile 1.3.7-KDevelop
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = libssh.kdevelop
|
||||
PROJECT_NUMBER = $VERSION$
|
||||
OUTPUT_DIRECTORY =
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = /home/aris/
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = /home/aris/dev/libssh-dev
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.idl \
|
||||
*.odl \
|
||||
*.cs \
|
||||
*.php \
|
||||
*.php3 \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.mm \
|
||||
*.C \
|
||||
*.CC \
|
||||
*.C++ \
|
||||
*.II \
|
||||
*.I++ \
|
||||
*.H \
|
||||
*.HH \
|
||||
*.H++ \
|
||||
*.CS \
|
||||
*.PHP \
|
||||
*.PHP3 \
|
||||
*.M \
|
||||
*.MM \
|
||||
*.C \
|
||||
*.H \
|
||||
*.tlh \
|
||||
*.diff \
|
||||
*.patch \
|
||||
*.moc \
|
||||
*.xpm \
|
||||
*.dox
|
||||
RECURSIVE = yes
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = yes
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE = libssh.tag
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
79
Makefile.in
Обычный файл
79
Makefile.in
Обычный файл
@ -0,0 +1,79 @@
|
||||
SHELL = /bin/sh
|
||||
VPATH = @srcdir@
|
||||
|
||||
subdirs = libssh/
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = $(exec_prefix)/bin
|
||||
incldir= $(prefix)/include
|
||||
infodir = $(prefix)/info
|
||||
libdir = $(prefix)/lib/
|
||||
mandir = $(prefix)/man/man1
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ -Iinclude/ -Wall -g
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = -lssh -Llibssh/
|
||||
INSTALL = @INSTALL@
|
||||
LN= @LN_S@
|
||||
OBJECTS= sample.o samplesshd.o
|
||||
VERSION=0.12-dev
|
||||
DISTLIB=libssh-$(VERSION)
|
||||
CONFIG=include/libssh/config.h
|
||||
all: $(CONFIG) $(OBJECTS)
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) all) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(CC) -o samplessh sample.o $(LDFLAGS) $(LIBS)
|
||||
$(LN) -sf samplessh samplesftp
|
||||
$(CC) -o samplesshd samplesshd.o $(LDFLAGS) $(LIBS)
|
||||
$(CONFIG):
|
||||
$(LN) -f ../../config.h $(CONFIG)
|
||||
dist:
|
||||
rm -fr $(DISTLIB)
|
||||
mkdir $(DISTLIB)
|
||||
cp Makefile.in configure.in configure config.h.in install-sh \
|
||||
mkinstalldirs config.sub config.guess $(DISTLIB)
|
||||
mkdir $(DISTLIB)/libssh
|
||||
mkdir $(DISTLIB)/include
|
||||
mkdir $(DISTLIB)/include/libssh
|
||||
mkdir $(DISTLIB)/doc
|
||||
cp libssh/Makefile.in $(DISTLIB)/libssh/
|
||||
cp libssh/*.c $(DISTLIB)/libssh/
|
||||
cp include/libssh/libssh.h include/libssh/sftp.h \
|
||||
include/libssh/priv.h \
|
||||
include/libssh/crypto.h include/libssh/ssh2.h \
|
||||
include/libssh/server.h $(DISTLIB)/include/libssh/
|
||||
cp *.c COPYING README AUTHORS CHANGELOG $(DISTLIB)/
|
||||
cp doc/* $(DISTLIB)/doc/
|
||||
tar czf $(DISTLIB).tgz $(DISTLIB)/
|
||||
install: all
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) install) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(top_srcdir)/mkinstalldirs $(incldir)/libssh
|
||||
$(INSTALL) include/libssh/libssh.h $(incldir)/libssh/
|
||||
$(INSTALL) include/libssh/config.h $(incldir)/libssh/
|
||||
$(INSTALL) include/libssh/sftp.h $(incldir)/libssh/
|
||||
$(INSTALL) include/libssh/crypto.h $(incldir)/libssh/
|
||||
$(INSTALL) include/libssh/server.h $(incldir)/libssh/
|
||||
$(INSTALL) include/libssh/ssh2.h $(incldir)/libssh/
|
||||
$(INSTALL) include/libssh/ssh1.h $(incldir)/libssh/
|
||||
clean:
|
||||
/bin/rm -f *~ *.o ssh sftp
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) clean) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
|
||||
distclean: clean
|
||||
/bin/rm -f Makefile config.h config.status config.cache config.log
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) distclean) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
|
39
README
Обычный файл
39
README
Обычный файл
@ -0,0 +1,39 @@
|
||||
The libSSH and its client
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-Aris Adamantiadis
|
||||
|
||||
1* Why ?
|
||||
-_-_-_-_-_
|
||||
|
||||
Why not ? :) I've began to work on my own implementation of the ssh protocol
|
||||
because i didn't like the currently public ones.
|
||||
Not any allow you to import and use the functions as a library, and so i
|
||||
worked on a library-based SSH implementation.
|
||||
|
||||
|
||||
2* How/Who ?
|
||||
-_-_-_-_-_-_-_
|
||||
|
||||
If you downloaded this file, you must know what it is : a library for
|
||||
accessing ssh client services through C libraries calls in a simple manner.
|
||||
The client is there as a programming example and isn't at all doing its job
|
||||
correctly (doesn't verify public key hashes with the ones in ~/.ssh/
|
||||
and doesn't handle TERM - yet)
|
||||
Everybody can use this software under the terms of the LGPL - see the COPYING
|
||||
file
|
||||
|
||||
3* What ?
|
||||
-_-_-_-_-_
|
||||
|
||||
The SSH library features :
|
||||
-Full C library functions for manipulating a client-side SSH connection
|
||||
-Fully configurable sessions
|
||||
-Support for AES-128,AES-192,AES-256,blowfish, in cbc mode
|
||||
-use multiple SSH connections in a same process, at same time.
|
||||
-usable SFTP implementation
|
||||
-Public key and password authentication
|
||||
|
||||
4* Where ?
|
||||
-_-_-_-_-_-_
|
||||
|
||||
http://0xbadc0de.be/?part=libssh
|
1415
config.guess
поставляемый
Исполняемый файл
1415
config.guess
поставляемый
Исполняемый файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
172
config.h.in
Обычный файл
172
config.h.in
Обычный файл
@ -0,0 +1,172 @@
|
||||
/* config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
#undef HAVE_DOPRNT
|
||||
|
||||
/* Define to 1 if you have the `endpwent' function. */
|
||||
#undef HAVE_ENDPWENT
|
||||
|
||||
/* Define to 1 if you have the <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
поставляемый
Исполняемый файл
1510
config.sub
поставляемый
Исполняемый файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
6195
configure
поставляемый
Исполняемый файл
6195
configure
поставляемый
Исполняемый файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
60
configure.in
Обычный файл
60
configure.in
Обычный файл
@ -0,0 +1,60 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.57)
|
||||
AC_INIT(libssh, 0.2-dev , aris@0xbadc0de.be)
|
||||
AC_CONFIG_SRCDIR([sample.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
||||
# Check for the OS.
|
||||
AC_CANONICAL_HOST
|
||||
case "$host" in
|
||||
*-apple*)
|
||||
DYLIB_EXTENSION="dylib"
|
||||
LIBSSH_LDFLAGS="-dynamiclib -prebind -seg1addr 0x3a000000 -install_name \"${libdir}/libssh.dylib\" -headerpad_max_install_names -current_version 0.1"
|
||||
;;
|
||||
*)
|
||||
DYLIB_EXTENSION="so"
|
||||
LIBSSH_LDFLAGS="-shared"
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(DYLIB_EXTENSION)
|
||||
AC_SUBST(LIBSSH_LDFLAGS)
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([crypto], [BN_init])
|
||||
AC_CHECK_LIB([z], [deflateInit_])
|
||||
AC_CHECK_LIB([resolv],[gethostbyname])
|
||||
AC_CHECK_LIB([nsl],[gethostbyname])
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h \
|
||||
sys/time.h termios.h unistd.h openssl/aes.h openssl/blowfish.h zlib.h \
|
||||
sys/poll.h ])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_HEADER_TIME
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_REALLOC
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS([endpwent gethostbyaddr gethostbyname getpass memmove memset \
|
||||
select socket strchr strdup strerror strstr poll])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
libssh/Makefile])
|
||||
AC_OUTPUT
|
886
doc/API.html
Обычный файл
886
doc/API.html
Обычный файл
@ -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
Обычный файл
107
doc/base64.txt
Обычный файл
@ -0,0 +1,107 @@
|
||||
The Base64 Content-Transfer-Encoding is designed to represent
|
||||
arbitrary sequences of octets in a form that need not be humanly
|
||||
readable. The encoding and decoding algorithms are simple, but the
|
||||
encoded data are consistently only about 33 percent larger than the
|
||||
unencoded data. This encoding is virtually identical to the one used
|
||||
in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421.
|
||||
The base64 encoding is adapted from RFC 1421, with one change: base64
|
||||
eliminates the "*" mechanism for embedded clear text.
|
||||
|
||||
A 65-character subset of US-ASCII is used, enabling 6 bits to be
|
||||
represented per printable character. (The extra 65th character, "=",
|
||||
is used to signify a special processing function.)
|
||||
|
||||
NOTE: This subset has the important property that it is
|
||||
represented identically in all versions of ISO 646, including US
|
||||
ASCII, and all characters in the subset are also represented
|
||||
identically in all versions of EBCDIC. Other popular encodings,
|
||||
such as the encoding used by the uuencode utility and the base85
|
||||
encoding specified as part of Level 2 PostScript, do not share
|
||||
these properties, and thus do not fulfill the portability
|
||||
requirements a binary transport encoding for mail must meet.
|
||||
|
||||
The encoding process represents 24-bit groups of input bits as output
|
||||
strings of 4 encoded characters. Proceeding from left to right, a
|
||||
24-bit input group is formed by concatenating 3 8-bit input groups.
|
||||
These 24 bits are then treated as 4 concatenated 6-bit groups, each
|
||||
of which is translated into a single digit in the base64 alphabet.
|
||||
When encoding a bit stream via the base64 encoding, the bit stream
|
||||
must be presumed to be ordered with the most-significant-bit first.
|
||||
|
||||
That is, the first bit in the stream will be the high-order bit in
|
||||
the first byte, and the eighth bit will be the low-order bit in the
|
||||
first byte, and so on.
|
||||
|
||||
Each 6-bit group is used as an index into an array of 64 printable
|
||||
characters. The character referenced by the index is placed in the
|
||||
output string. These characters, identified in Table 1, below, are
|
||||
selected so as to be universally representable, and the set excludes
|
||||
characters with particular significance to SMTP (e.g., ".", CR, LF)
|
||||
and to the encapsulation boundaries defined in this document (e.g.,
|
||||
"-").
|
||||
|
||||
Table 1: The Base64 Alphabet
|
||||
|
||||
Value Encoding Value Encoding Value Encoding Value Encoding
|
||||
0 A 17 R 34 i 51 z
|
||||
1 B 18 S 35 j 52 0
|
||||
2 C 19 T 36 k 53 1
|
||||
3 D 20 U 37 l 54 2
|
||||
4 E 21 V 38 m 55 3
|
||||
5 F 22 W 39 n 56 4
|
||||
6 G 23 X 40 o 57 5
|
||||
7 H 24 Y 41 p 58 6
|
||||
8 I 25 Z 42 q 59 7
|
||||
9 J 26 a 43 r 60 8
|
||||
10 K 27 b 44 s 61 9
|
||||
11 L 28 c 45 t 62 +
|
||||
12 M 29 d 46 u 63 /
|
||||
13 N 30 e 47 v
|
||||
14 O 31 f 48 w (pad) =
|
||||
15 P 32 g 49 x
|
||||
16 Q 33 h 50 y
|
||||
The output stream (encoded bytes) must be represented in lines of no
|
||||
more than 76 characters each. All line breaks or other characters
|
||||
not found in Table 1 must be ignored by decoding software. In base64
|
||||
data, characters other than those in Table 1, line breaks, and other
|
||||
white space probably indicate a transmission error, about which a
|
||||
warning message or even a message rejection might be appropriate
|
||||
under some circumstances.
|
||||
|
||||
Special processing is performed if fewer than 24 bits are available
|
||||
at the end of the data being encoded. A full encoding quantum is
|
||||
always completed at the end of a body. When fewer than 24 input bits
|
||||
are available in an input group, zero bits are added (on the right)
|
||||
to form an integral number of 6-bit groups. Padding at the end of
|
||||
the data is performed using the '=' character. Since all base64
|
||||
input is an integral number of octets, only the following cases can
|
||||
arise: (1) the final quantum of encoding input is an integral
|
||||
multiple of 24 bits; here, the final unit of encoded output will be
|
||||
an integral multiple of 4 characters with no "=" padding, (2) the
|
||||
final quantum of encoding input is exactly 8 bits; here, the final
|
||||
unit of encoded output will be two characters followed by two "="
|
||||
padding characters, or (3) the final quantum of encoding input is
|
||||
exactly 16 bits; here, the final unit of encoded output will be three
|
||||
characters followed by one "=" padding character.
|
||||
|
||||
Because it is used only for padding at the end of the data, the
|
||||
occurrence of any '=' characters may be taken as evidence that the
|
||||
end of the data has been reached (without truncation in transit). No
|
||||
such assurance is possible, however, when the number of octets
|
||||
transmitted was a multiple of three.
|
||||
|
||||
Any characters outside of the base64 alphabet are to be ignored in
|
||||
base64-encoded data. The same applies to any illegal sequence of
|
||||
characters in the base64 encoding, such as "====="
|
||||
|
||||
Care must be taken to use the proper octets for line breaks if base64
|
||||
encoding is applied directly to text material that has not been
|
||||
converted to canonical form. In particular, text line breaks must be
|
||||
converted into CRLF sequences prior to base64 encoding. The important
|
||||
thing to note is that this may be done directly by the encoder rather
|
||||
than in a prior canonicalization step in some implementations.
|
||||
|
||||
NOTE: There is no need to worry about quoting apparent
|
||||
encapsulation boundaries within base64-encoded parts of multipart
|
||||
entities because no hyphen characters are used in the base64
|
||||
encoding.
|
647
doc/draft-ietf-secsh-agent-01.txt
Обычный файл
647
doc/draft-ietf-secsh-agent-01.txt
Обычный файл
@ -0,0 +1,647 @@
|
||||
Network Working Group Tatu Ylonen
|
||||
INTERNET-DRAFT Timo J. Rinne
|
||||
draft-ietf-secsh-agent-01.txt Sami Lehtinen
|
||||
Expires in six months SSH Communications Security
|
||||
20 November, 2002
|
||||
|
||||
|
||||
|
||||
Secure Shell Authentication Agent Protocol
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance
|
||||
with all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as
|
||||
Internet-Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six
|
||||
months and may be updated, replaced, or obsoleted by other
|
||||
documents at any time. It is inappropriate to use Internet-
|
||||
Drafts as reference material or to cite them other than as
|
||||
"work in progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at
|
||||
http://www.ietf.org/ietf/1id-abstracts.txt
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes the Secure Shell authentication agent protocol
|
||||
(i.e., the protocol used between a client requesting authentication and
|
||||
the authentication agent). This protocol usually runs in a machine-spe-
|
||||
cific local channel or over a forwarded authentication channel. It is
|
||||
assumed that the channel is trusted, so no protection for the communica-
|
||||
tions channel is provided by this protocol.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 1]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Authentication Agent Protocol . . . . . . . . . . . . . . . . . 2
|
||||
1.1. Packet Format . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
1.2. Forwarding Notices . . . . . . . . . . . . . . . . . . . . . 3
|
||||
1.3. Requesting Version Number . . . . . . . . . . . . . . . . . 3
|
||||
1.4. Adding Keys to the Agent . . . . . . . . . . . . . . . . . . 4
|
||||
1.5. Deleting Keys from the Agent . . . . . . . . . . . . . . . . 5
|
||||
1.6. Deleting specific key from the Agent . . . . . . . . . . . . 5
|
||||
1.7. Listing the Keys that the Agent Can Use . . . . . . . . . . 6
|
||||
2. Performing Private Key Operations . . . . . . . . . . . . . . . 6
|
||||
2.1. Signing . . . . . . . . . . . . . . . . . . . . . . . . . . 7
|
||||
2.2. Decrypting . . . . . . . . . . . . . . . . . . . . . . . . . 7
|
||||
2.3. Secure Shell Challenge-Response Authentication . . . . . . . 7
|
||||
3. Administrative Messages . . . . . . . . . . . . . . . . . . . . 7
|
||||
3.1. Locking and unlocking the agent . . . . . . . . . . . . . . 8
|
||||
3.2. Miscellaneous Agent Commands . . . . . . . . . . . . . . . . 8
|
||||
4. Agent Forwarding With Secure Shell . . . . . . . . . . . . . . . 9
|
||||
4.1. Requesting Agent Forwarding . . . . . . . . . . . . . . . . 9
|
||||
4.2. Agent Forwarding Channels . . . . . . . . . . . . . . . . . 9
|
||||
5. Security Considerations . . . . . . . . . . . . . . . . . . . . 9
|
||||
6. Intellectual Property . . . . . . . . . . . . . . . . . . . . . 10
|
||||
7. Additional Information . . . . . . . . . . . . . . . . . . . . . 10
|
||||
8. References . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
|
||||
9. Address of Authors . . . . . . . . . . . . . . . . . . . . . . . 10
|
||||
|
||||
|
||||
|
||||
1. Authentication Agent Protocol
|
||||
|
||||
The authentication agent is a piece of software that runs in a user's
|
||||
local workstation, laptop, or other trusted device. It is used to
|
||||
implement single sign-on. It holds the user's private keys in its own
|
||||
storage, and can perform requested operations using the private key. It
|
||||
allows the keys to be kept on a smartcard or other special hardware that
|
||||
can perform cryptographic operations.
|
||||
|
||||
The authentication agent protocol is used to communicate between the
|
||||
authentication agent and clients wanting to authenticate something or
|
||||
wanting to perform private key operations.
|
||||
|
||||
The actual communication between the client and the agent happens using
|
||||
a machine-dependent trusted communications channel. This channel would
|
||||
typically be a local socket, named pipe, or some kind of secure
|
||||
messaging system that works inside the local machine.
|
||||
|
||||
The protocol works by the client sending requests to the agent, and the
|
||||
agent responding to these requests.
|
||||
|
||||
1.1. Packet Format
|
||||
|
||||
All messages passed to/from the authentication agent have the following
|
||||
format:
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 2]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
uint32 length
|
||||
byte type
|
||||
data[length -1] data payload
|
||||
|
||||
The following packet types are currently defined:
|
||||
|
||||
/* Messages sent by the client. */
|
||||
#define SSH_AGENT_REQUEST_VERSION 1
|
||||
#define SSH_AGENT_ADD_KEY 202
|
||||
#define SSH_AGENT_DELETE_ALL_KEYS 203
|
||||
#define SSH_AGENT_LIST_KEYS 204
|
||||
#define SSH_AGENT_PRIVATE_KEY_OP 205
|
||||
#define SSH_AGENT_FORWARDING_NOTICE 206
|
||||
#define SSH_AGENT_DELETE_KEY 207
|
||||
#define SSH_AGENT_LOCK 208
|
||||
#define SSH_AGENT_UNLOCK 209
|
||||
#define SSH_AGENT_PING 212
|
||||
#define SSH_AGENT_RANDOM 213
|
||||
|
||||
/* Messages sent by the agent. */
|
||||
#define SSH_AGENT_SUCCESS 101
|
||||
#define SSH_AGENT_FAILURE 102
|
||||
#define SSH_AGENT_VERSION_RESPONSE 103
|
||||
#define SSH_AGENT_KEY_LIST 104
|
||||
#define SSH_AGENT_OPERATION_COMPLETE 105
|
||||
#define SSH_AGENT_RANDOM_DATA 106
|
||||
#define SSH_AGENT_ALIVE 150
|
||||
|
||||
1.2. Forwarding Notices
|
||||
|
||||
If the agent connection is forwarded through intermediate hosts (using
|
||||
the SSH Connection Protocol agent forwarding feature (described in
|
||||
Section ``Agent Forwarding With Secure Shell'' of this document), or
|
||||
some other means), each intermediate node (Secure Shell client) should
|
||||
insert the following message into the agent channel before forwarding
|
||||
any other messages. The real agent will then receive these messages in
|
||||
sequence the nearest node first, and can determine whether the
|
||||
connection is from a local machine and if not, can log the path where
|
||||
the connection came from. These messages must be wrapped in the
|
||||
appropriate header.
|
||||
|
||||
byte SSH_AGENT_FORWARDING_NOTICE
|
||||
string remote host name (as typed by the user, preferably)
|
||||
string remote host ip
|
||||
uint32 remote host port
|
||||
|
||||
1.3. Requesting Version Number
|
||||
|
||||
When the client opens a connection, it must send the following message
|
||||
to the server. This must be the first message sent. The real agent
|
||||
will receive this after zero or more forwarding notice messages.
|
||||
byte SSH_AGENT_REQUEST_VERSION
|
||||
string version string of the application sending the request
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 3]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
(optional)
|
||||
|
||||
If the agent follows this protocol, it will respond with
|
||||
|
||||
byte SSH_AGENT_VERSION_RESPONSE
|
||||
uint32 version number, 2 for this protocol
|
||||
|
||||
If the version number request is ever sent to the Secure Shell 1.x
|
||||
agent, it will interpret it as a request to list identities. It will
|
||||
then respond with a message whose first byte is 2. This can be used to
|
||||
determine the version of the agent if compatibility with Secure Shell
|
||||
1.x is desired.
|
||||
|
||||
If the version string query arrives without trailing string identifying
|
||||
the client software version, it can be translated list identities
|
||||
request sent by Secure Shell 1.x and handled accordingly. If agent
|
||||
software does not support the agent protocol of Secure Shell 1.x, it MAY
|
||||
also interpret this query as valid SSH_AGENT_REQUEST_VERSION packet.
|
||||
|
||||
1.4. Adding Keys to the Agent
|
||||
|
||||
The client can add a new private key to the agent with the following
|
||||
message.
|
||||
|
||||
byte SSH_AGENT_ADD_KEY
|
||||
string private key blob with empty passphrase
|
||||
string public key and/or certificates for it
|
||||
string description of the key
|
||||
... 0, 1 or several constraints follow
|
||||
|
||||
All constraints are pairs of following format:
|
||||
|
||||
byte SSH_AGENT_CONSTRAINT_*
|
||||
variable argument for the constraint
|
||||
|
||||
The type of the argument is dependent on the constraint type. Following
|
||||
constraint types are currently defined:
|
||||
|
||||
/* Constraints 50-99 have a uint32 argument */
|
||||
|
||||
/* Argument is uint32 defining key expiration time-out in
|
||||
seconds. After this timeout expires, the key can't be used.
|
||||
0 == no timeout */
|
||||
#define SSH_AGENT_CONSTRAINT_TIMEOUT 50
|
||||
|
||||
/* Argument is uint32 defining the number of operations that can
|
||||
be performed with this key. 0xffffffff == no limit */
|
||||
#define SSH_AGENT_CONSTRAINT_USE_LIMIT 51
|
||||
|
||||
/* Argument is uint32 defining the number of forwarding steps that
|
||||
this key can be forwarded. 0xffffffff == no limit */
|
||||
#define SSH_AGENT_CONSTRAINT_FORWARDING_STEPS 52
|
||||
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 4]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
/* Constraints 100-149 have a string argument */
|
||||
|
||||
/* Argument is string defining the allowed forwarding steps for
|
||||
this key. XXX define this. */
|
||||
#define SSH_AGENT_CONSTRAINT_FORWARDING_PATH 100
|
||||
|
||||
/* Constraints 150-199 have a boolean argument */
|
||||
|
||||
/* Argument is a boolean telling whether the key can be used
|
||||
in Secure Shell 1.x compatibility operations. */
|
||||
|
||||
#define SSH_AGENT_CONSTRAINT_SSH1_COMPAT 150
|
||||
|
||||
/* Argument is a boolean telling whether operations performed
|
||||
with this key should be confirmed interactively by the user
|
||||
or not. */
|
||||
#define SSH_AGENT_CONSTRAINT_NEED_USER_VERIFICATION 151
|
||||
|
||||
Message can contain zero, one or multiple constraints.
|
||||
|
||||
If the operation is successful, the agent will respond with the
|
||||
following message.
|
||||
|
||||
byte SSH_AGENT_SUCCESS
|
||||
|
||||
If the operation fails for some reason, the following message will be
|
||||
returned instead.
|
||||
|
||||
byte SSH_AGENT_FAILURE
|
||||
uint32 error code
|
||||
|
||||
The error code is one of the following:
|
||||
|
||||
#define SSH_AGENT_ERROR_TIMEOUT 1
|
||||
#define SSH_AGENT_ERROR_KEY_NOT_FOUND 2
|
||||
#define SSH_AGENT_ERROR_DECRYPT_FAILED 3
|
||||
#define SSH_AGENT_ERROR_SIZE_ERROR 4
|
||||
#define SSH_AGENT_ERROR_KEY_NOT_SUITABLE 5
|
||||
#define SSH_AGENT_ERROR_DENIED 6
|
||||
#define SSH_AGENT_ERROR_FAILURE 7
|
||||
#define SSH_AGENT_ERROR_UNSUPPORTED_OP 8
|
||||
|
||||
1.5. Deleting Keys from the Agent
|
||||
|
||||
All keys that are in possession of the agent can be deleted with the
|
||||
following message. (The client is allowed to ignore this for some keys
|
||||
if desired.)
|
||||
|
||||
byte SSH_AGENT_DELETE_ALL_KEYS
|
||||
|
||||
The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE.
|
||||
|
||||
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 5]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
1.6. Deleting specific key from the Agent
|
||||
|
||||
The client can delete a specific key with given public key with
|
||||
following message.
|
||||
|
||||
byte SSH_AGENT_DELETE_KEY
|
||||
string public key and/or certificates for it
|
||||
string description of the key
|
||||
|
||||
The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE.
|
||||
|
||||
1.7. Listing the Keys that the Agent Can Use
|
||||
|
||||
The following message requests a list of all keys that the agent can
|
||||
use.
|
||||
|
||||
byte SSH_AGENT_LIST_KEYS
|
||||
|
||||
The agent will respond with the following message.
|
||||
|
||||
byte SSH_AGENT_KEY_LIST
|
||||
uint32 number_of_keys
|
||||
repeats number_of_keys times:
|
||||
string public key blob or certificates
|
||||
string description
|
||||
|
||||
2. Performing Private Key Operations
|
||||
|
||||
The real purpose of the agent is to perform private key operations.
|
||||
Such operations are performed with the following message.
|
||||
|
||||
byte SSH_AGENT_PRIVATE_KEY_OP
|
||||
string operation name
|
||||
string key or certificates, as returned in SSH_AGENT_KEY_LIST
|
||||
... operation-specific data follows
|
||||
|
||||
The operation to be performed is identified by a name (string). Custom
|
||||
operations can be added by suffixing the operation name by the fully
|
||||
qualified domain name of the person/organization adding the new
|
||||
operation.
|
||||
|
||||
When the operation is complete, the agent will respond with either
|
||||
SSH_AGENT_FAILURE or with the following message if the operation is
|
||||
successful:
|
||||
|
||||
byte SSH_AGENT_OPERATION_COMPLETE
|
||||
string resulting data
|
||||
|
||||
If an operation is attempted that is not supported by the agent, the
|
||||
agent will respond with SSH_AGENT_FAILURE with error code set to
|
||||
SSH_AGENT_ERROR_UNSUPPORTED_OP.
|
||||
|
||||
The standard operations are defined below.
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 6]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
2.1. Signing
|
||||
|
||||
The agent can be used to create a digital signature using a key held by
|
||||
the agent. The operation name is "sign", and data in is a hash
|
||||
(suitable for the key) that is to be signed. This normally performs the
|
||||
raw private key operation, without hashing data first. The resulting
|
||||
data will be a binary representation of the output of the private key
|
||||
operation. The exact details of the operations to be performed depend
|
||||
on the key being used.
|
||||
|
||||
The operation-specific data has the following format:
|
||||
|
||||
string data to be signed
|
||||
|
||||
Alternatively, it is possible to give the actual data to be signed to
|
||||
the agent. This is done using the operation "hash-and-sign". This is
|
||||
otherwise equal, but performs key-dependent hashing before signing.
|
||||
|
||||
If the requested operation is not legal for the key, SSH_AGENT_FAILURE
|
||||
will be returned with error code set to
|
||||
SSH_AGENT_ERROR_KEY_NOT_SUITABLE.
|
||||
|
||||
2.2. Decrypting
|
||||
|
||||
The agent can be used to decrypt a public key encrypted message with the
|
||||
operation "decrypt". This takes in raw public-key encrypted data, and
|
||||
returns the resulting decrypted data.
|
||||
|
||||
This may also fail. If the requested operation is not legal for the
|
||||
key, error code is set to SSH_AGENT_ERROR_KEY_NOT_SUITABLE.
|
||||
|
||||
The operation-specific data has the following format:
|
||||
|
||||
string data to be decrypted
|
||||
|
||||
2.3. Secure Shell Challenge-Response Authentication
|
||||
|
||||
Performs Secure Shell challenge-response authentication. This operation
|
||||
has the name "ssh1-challenge-response".
|
||||
|
||||
This operation works by first decrypting the challenge, then computing
|
||||
MD5 of the concatenation of the decrypted challenge and the session id
|
||||
(in this order), and returns the resulting 16 byte hash. The operation-
|
||||
specific data is in the following format:
|
||||
|
||||
string challenge encrypted using the public key
|
||||
string session id
|
||||
|
||||
Normally, the length of the challenge before encryption will be 32 bytes
|
||||
and the length of the session id 16 bytes. The length of the encrypted
|
||||
challenge depends on the key and algorithm used.
|
||||
|
||||
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 7]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
3. Administrative Messages
|
||||
|
||||
There are also a number of messages that are only used to administer the
|
||||
agent. These might e.g. be used by a user interface for the agent. The
|
||||
agent should only allow these messages from local connection (i.e., if
|
||||
no forwarding notice messages were received before the version number
|
||||
request).
|
||||
|
||||
3.1. Locking and unlocking the agent
|
||||
|
||||
The agent can be temporarily locked by message:
|
||||
|
||||
byte SSH_AGENT_LOCK
|
||||
string locking password
|
||||
|
||||
The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE.
|
||||
Particularily SSH_AGENT_FAILURE is sent, if agent is already locked.
|
||||
After this message, agent responds to all commands with
|
||||
SSH_AGENT_FAILURE until it receives a following command.
|
||||
|
||||
byte SSH_AGENT_UNLOCK
|
||||
string locking password
|
||||
|
||||
The agent responds with either SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE.
|
||||
Particularily SSH_AGENT_FAILURE is sent, if agent is not locked or if
|
||||
the submitted password does not match with one given with SSH_AGENT_LOCK
|
||||
message.
|
||||
|
||||
3.2. Miscellaneous Agent Commands
|
||||
|
||||
byte SSH_AGENT_PING
|
||||
... arbitrary padding data
|
||||
|
||||
Any agent or client receiving this message, should respond with
|
||||
|
||||
byte SSH_AGENT_ALIVE
|
||||
... padding data from the SSH_AGENT_PING request
|
||||
|
||||
where the padding data is identical to the data sent with
|
||||
SSH_AGENT_PING.
|
||||
|
||||
byte SSH_AGENT_RANDOM
|
||||
uint32 the length of the requested random buffer
|
||||
|
||||
Client can request random data from the agent by this message. Agent
|
||||
responds either with SSH_AGENT_RANDOM_DATA or SSH_AGENT_FAILURE message.
|
||||
|
||||
byte SSH_AGENT_RANDOM_DATA
|
||||
string random data
|
||||
|
||||
This message is a successful response to SSH_AGENT_RANDOM message.
|
||||
Message contains the random string of requested length.
|
||||
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 8]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
4. Agent Forwarding With Secure Shell
|
||||
|
||||
The agent connection is typically forwarded over a Secure Shell
|
||||
connection. This requires small additions to the SSH Connection Protocol
|
||||
[SSH-CONN].
|
||||
|
||||
4.1. Requesting Agent Forwarding
|
||||
|
||||
Agent forwarding may be requested for a session by sending
|
||||
|
||||
byte SSH_MSG_CHANNEL_REQUEST
|
||||
uint32 recipient channel
|
||||
string "auth-agent-req"
|
||||
boolean want reply
|
||||
|
||||
This will, on success, create an agent listener to the remote end.
|
||||
|
||||
4.2. Agent Forwarding Channels
|
||||
|
||||
When a connection comes to the forwarded agent listener, a channel is
|
||||
opened to forward the connection to the other side.
|
||||
|
||||
byte SSH_MSG_CHANNEL_OPEN
|
||||
string "auth-agent"
|
||||
uint32 sender channel
|
||||
uint32 initial window size
|
||||
uint32 maximum packet size
|
||||
|
||||
Implementations MUST reject these messages unless they have previously
|
||||
requested agent forwarding.
|
||||
|
||||
Forwarded agent channels are independent of any sessions, and closing a
|
||||
session channel does not in any way imply that forwarded connections
|
||||
should be closed.
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
The authentication agent is used to control security-sensitive
|
||||
operations, and is used to implement single sign-on.
|
||||
|
||||
Anyone with access to the authentication agent can perform private key
|
||||
operations with the agent. This is a power equivalent to possession of
|
||||
the private key as long as the connection to the key is maintained. It
|
||||
is not possible to retrieve the key from the agent.
|
||||
|
||||
It is recommended that agent implementations allow and perform some form
|
||||
of logging and access control. This access control may utilize
|
||||
information about the path through which the connection was received (as
|
||||
collected with SSH_AGENT_FORWARDING_NOTICE messages; however, the path
|
||||
is reliable only up to and including the first unreliable machine.).
|
||||
Implementations should also allow restricting the operations that can be
|
||||
performed with keys - e.g., limiting them to challenge-response only.
|
||||
|
||||
|
||||
|
||||
Tatu Ylonen, Timo J. Rinne and Sami Lehtinen [page 9]
|
||||
|
||||
INTERNET-DRAFT 20 November, 2002
|
||||
|
||||
One should note that a local superuser will be able to obtain access to
|
||||
agents running on the local machine. This cannot be prevented; in most
|
||||
operating systems, a user with sufficient privileges will be able to
|
||||
read the keys from the physical memory.
|
||||
|
||||
The authentication agent should not be run or forwarded to machine whose
|
||||
integrity is not trusted, as security on such machines might be
|
||||
compromised and might allow an attacker to obtain unauthorized access to
|
||||
the agent.
|
||||
|
||||
6. Intellectual Property
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
intellectual property or other rights that might be claimed to pertain
|
||||
to the implementation or use of the technology described in this
|
||||
document or the extent to which any license under such rights might or
|
||||
might not be available; neither does it represent that it has made any
|
||||
effort to identify any such rights. Information on the IETF's
|
||||
procedures with respect to rights in standards-track and standards-
|
||||
related documentation can be found in BCP-11. Copies of claims of
|
||||
rights made available for publication and any assurances of licenses to
|
||||
be made available, or the result of an attempt made to obtain a general
|
||||
license or permission for the use of such proprietary rights by
|
||||
implementers or users of this specification can be obtained from the
|
||||
IETF Secretariat.
|
||||
|
||||
The IETF has been notified of intellectual property rights claimed in
|
||||
regard to some or all of the specification contained in this document.
|
||||
For more information consult the online list of claimed rights.
|
||||
|
||||
7. Additional Information
|
||||
|
||||
The current document editor is: Sami Lehtinen <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
Обычный файл
1736
doc/draft-ietf-secsh-architecture-14.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
559
doc/draft-ietf-secsh-assignednumbers-04.txt
Обычный файл
559
doc/draft-ietf-secsh-assignednumbers-04.txt
Обычный файл
@ -0,0 +1,559 @@
|
||||
Network Working Group S. Lehtinen
|
||||
Internet-Draft SSH Communications Security Corp
|
||||
Expires: February 13, 2004 D. Moffat
|
||||
Sun Microsystems
|
||||
August 15, 2003
|
||||
|
||||
|
||||
SSH Protocol Assigned Numbers
|
||||
draft-ietf-secsh-assignednumbers-04.txt
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as Internet-
|
||||
Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at
|
||||
http://www.ietf.org/ietf/1id-abstracts.txt.
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
This Internet-Draft will expire on February 13, 2004.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
Abstract
|
||||
|
||||
This document defines the initial state of the IANA assigned numbers
|
||||
for the SSH protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-
|
||||
CONNECT], [SSH-USERAUTH]. Except for one HISTORIC algorithm
|
||||
generally regarded as obsolete, this document does not define any new
|
||||
protocols or any number ranges not already defined in the above
|
||||
referenced documents. It is intended only for initalization of the
|
||||
IANA databases referenced in those documents.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 1]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Message Numbers . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
1.1 Disconnect Codes . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
2. Service Names . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
2.1 Authentication Method Names . . . . . . . . . . . . . . . . 5
|
||||
2.2 Connection Protocol Assigned Names . . . . . . . . . . . . . 6
|
||||
2.2.1 Connection Protocol Channel Types . . . . . . . . . . . . . 6
|
||||
2.2.2 Connection Protocol Global Request Names . . . . . . . . . . 6
|
||||
2.2.3 Connection Protocol Channel Request Names . . . . . . . . . 6
|
||||
3. Key Exchange Method Names . . . . . . . . . . . . . . . . . 7
|
||||
4. Assigned Algorithm Names . . . . . . . . . . . . . . . . . . 7
|
||||
4.1 Encryption Algorithm Names . . . . . . . . . . . . . . . . . 7
|
||||
4.2 MAC Algorithm Names . . . . . . . . . . . . . . . . . . . . 8
|
||||
4.3 Public Key Algorithm Names . . . . . . . . . . . . . . . . . 8
|
||||
4.4 Compression Algorithm Names . . . . . . . . . . . . . . . . 8
|
||||
References . . . . . . . . . . . . . . . . . . . . . . . . . 8
|
||||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 9
|
||||
Full Copyright Statement . . . . . . . . . . . . . . . . . . 10
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 2]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
1. Message Numbers
|
||||
|
||||
The Message Number is an 8-bit value, which describes the payload of
|
||||
a packet.
|
||||
|
||||
Protocol packets have message numbers in the range 1 to 255. These
|
||||
numbers have been allocated as follows in [SSH-ARCH]:
|
||||
|
||||
Transport layer protocol:
|
||||
|
||||
1 to 19 Transport layer generic (e.g. disconnect, ignore, debug, etc.)
|
||||
20 to 29 Algorithm negotiation
|
||||
30 to 49 Key exchange method specific (numbers can be reused for
|
||||
different authentication methods)
|
||||
|
||||
User authentication protocol:
|
||||
|
||||
50 to 59 User authentication generic
|
||||
60 to 79 User authentication method specific (numbers can be
|
||||
reused for different authentication methods)
|
||||
|
||||
Connection protocol:
|
||||
|
||||
80 to 89 Connection protocol generic
|
||||
90 to 127 Channel related messages
|
||||
|
||||
Reserved for client protocols:
|
||||
|
||||
128 to 191 Reserved
|
||||
|
||||
Local extensions:
|
||||
|
||||
192 to 255 Local extensions
|
||||
|
||||
|
||||
Requests for assignments of new message numbers must be accompanied
|
||||
by an RFC which describes the new packet type. If the RFC is not on
|
||||
the standards-track (i.e. it is an informational or experimental
|
||||
RFC), it must be explicitly reviewed and approved by the IESG before
|
||||
the RFC is published and the message number is assigned.
|
||||
|
||||
Message ID Value Reference
|
||||
----------- ----- ---------
|
||||
SSH_MSG_DISCONNECT 1 [SSH-TRANS]
|
||||
SSH_MSG_IGNORE 2 [SSH-TRANS]
|
||||
SSH_MSG_UNIMPLEMENTED 3 [SSH-TRANS]
|
||||
SSH_MSG_DEBUG 4 [SSH-TRANS]
|
||||
SSH_MSG_SERVICE_REQUEST 5 [SSH-TRANS]
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 3]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
SSH_MSG_SERVICE_ACCEPT 6 [SSH-TRANS]
|
||||
SSH_MSG_KEXINIT 20 [SSH-TRANS]
|
||||
SSH_MSG_NEWKEYS 21 [SSH-TRANS]
|
||||
SSH_MSG_KEXDH_INIT 30 [SSH-TRANS]
|
||||
SSH_MSG_KEXDH_REPLY 31 [SSH-TRANS]
|
||||
SSH_MSG_USERAUTH_REQUEST 50 [SSH-USERAUTH]
|
||||
SSH_MSG_USERAUTH_FAILURE 51 [SSH-USERAUTH]
|
||||
SSH_MSG_USERAUTH_SUCCESS 52 [SSH-USERAUTH]
|
||||
SSH_MSG_USERAUTH_BANNER 53 [SSH-USERAUTH]
|
||||
SSH_MSG_USERAUTH_PK_OK 60 [SSH-USERAUTH]
|
||||
SSH_MSG_GLOBAL_REQUEST 80 [SSH-CONNECT]
|
||||
SSH_MSG_REQUEST_SUCCESS 81 [SSH-CONNECT]
|
||||
SSH_MSG_REQUEST_FAILURE 82 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_OPEN 90 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_OPEN_FAILURE 92 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_WINDOW_ADJUST 93 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_DATA 94 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_EXTENDED_DATA 95 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_EOF 96 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_CLOSE 97 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_REQUEST 98 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_SUCCESS 99 [SSH-CONNECT]
|
||||
SSH_MSG_CHANNEL_FAILURE 100 [SSH-CONNECT]
|
||||
|
||||
|
||||
1.1 Disconnect Codes
|
||||
|
||||
The Disconnect code is an 8-bit value, which describes the disconnect
|
||||
reason. Requests for assignments of new disconnect codes must be
|
||||
accompanied by an RFC which describes the new disconnect reason code.
|
||||
|
||||
|
||||
Disconnect code Value Reference
|
||||
---------------- ----- ---------
|
||||
SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 [SSH-TRANS]
|
||||
SSH_DISCONNECT_PROTOCOL_ERROR 2 [SSH-TRANS]
|
||||
SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 [SSH-TRANS]
|
||||
SSH_DISCONNECT_RESERVED 4 [SSH-TRANS]
|
||||
SSH_DISCONNECT_MAC_ERROR 5 [SSH-TRANS]
|
||||
SSH_DISCONNECT_COMPRESSION_ERROR 6 [SSH-TRANS]
|
||||
SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 [SSH-TRANS]
|
||||
SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 [SSH-TRANS]
|
||||
SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 [SSH-TRANS]
|
||||
SSH_DISCONNECT_CONNECTION_LOST 10 [SSH-TRANS]
|
||||
SSH_DISCONNECT_BY_APPLICATION 11 [SSH-TRANS]
|
||||
SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 [SSH-TRANS]
|
||||
SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 [SSH-TRANS]
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 4]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 [SSH-TRANS]
|
||||
SSH_DISCONNECT_ILLEGAL_USER_NAME 15 [SSH-TRANS]
|
||||
|
||||
|
||||
2. Service Names
|
||||
|
||||
The Service Name is used to describe a protocol layer. These names
|
||||
MUST be printable US-ASCII strings, and MUST NOT contain the
|
||||
characters at-sign ('@'), comma (','), or whitespace or control
|
||||
characters (ASCII codes 32 or less). Names are case-sensitive, and
|
||||
MUST NOT be longer than 64 characters.
|
||||
|
||||
Requests for assignments of new service names must be accompanied by
|
||||
an RFC which describes the interpretation for the service name. If
|
||||
the RFC is not on the standards-track (i.e. it is an informational
|
||||
or experimental RFC), it must be explicitly reviewed and approved by
|
||||
the IESG before the RFC is published and the service name is
|
||||
assigned.
|
||||
|
||||
Service name Reference
|
||||
------------- ---------
|
||||
ssh-userauth [SSH-USERAUTH]
|
||||
ssh-connection [SSH-CONNECT]
|
||||
|
||||
|
||||
2.1 Authentication Method Names
|
||||
|
||||
The Authentication Method Name is used to describe an authentication
|
||||
method for the "ssh-userauth" service [SSH-USERAUTH]. These names
|
||||
MUST be printable US-ASCII strings, and MUST NOT contain the
|
||||
characters at-sign ('@'), comma (','), or whitespace or control
|
||||
characters (ASCII codes 32 or less). Names are case-sensitive, and
|
||||
MUST NOT be longer than 64 characters.
|
||||
|
||||
Requests for assignments of new authentication method names must be
|
||||
accompanied by an RFC which describes the interpretation for the
|
||||
authentication method.
|
||||
|
||||
Method name Reference
|
||||
------------ ---------
|
||||
publickey [SSH-USERAUTH, Section 4]
|
||||
password [SSH-USERAUTH, Section 5]
|
||||
hostbased [SSH-USERAUTH, Section 6]
|
||||
none [SSH-USERAUTH, Section 2.3]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 5]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
2.2 Connection Protocol Assigned Names
|
||||
|
||||
The following request and type names MUST be printable US-ASCII
|
||||
strings, and MUST NOT contain the characters at-sign ('@'), comma
|
||||
(','), or whitespace or control characters (ASCII codes 32 or less).
|
||||
Names are case-sensitive, and MUST NOT be longer than 64 characters.
|
||||
|
||||
Requests for assignments of new assigned names must be accompanied by
|
||||
an RFC which describes the interpretation for the type or request.
|
||||
|
||||
2.2.1 Connection Protocol Channel Types
|
||||
|
||||
Channel type Reference
|
||||
------------ ---------
|
||||
session [SSH-CONNECT, Section 4.1]
|
||||
x11 [SSH-CONNECT, Section 4.3.2]
|
||||
forwarded-tcpip [SSH-CONNECT, Section 5.2]
|
||||
direct-tcpip [SSH-CONNECT, Section 5.2]
|
||||
|
||||
|
||||
2.2.2 Connection Protocol Global Request Names
|
||||
|
||||
Request type Reference
|
||||
------------ ---------
|
||||
tcpip-forward [SSH-CONNECT, Section 5.1]
|
||||
cancel-tcpip-forward [SSH-CONNECT, Section 5.1]
|
||||
|
||||
|
||||
2.2.3 Connection Protocol Channel Request Names
|
||||
|
||||
Request type Reference
|
||||
------------ ---------
|
||||
pty-req [SSH-CONNECT, Section 4.2]
|
||||
x11-req [SSH-CONNECT, Section 4.3.1]
|
||||
env [SSH-CONNECT, Section 4.4]
|
||||
shell [SSH-CONNECT, Section 4.5]
|
||||
exec [SSH-CONNECT, Section 4.5]
|
||||
subsystem [SSH-CONNECT, Section 4.5]
|
||||
window-change [SSH-CONNECT, Section 4.7]
|
||||
xon-xoff [SSH-CONNECT, Section 4.8]
|
||||
signal [SSH-CONNECT, Section 4.9]
|
||||
exit-status [SSH-CONNECT, Section 4.10]
|
||||
exit-signal [SSH-CONNECT, Section 4.10]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 6]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
3. Key Exchange Method Names
|
||||
|
||||
The Key Exchange Method Name describes a key-exchange method for the
|
||||
protocol [SSH-TRANS]. The names MUST be printable US-ASCII strings,
|
||||
and MUST NOT contain the characters at-sign ('@'), comma (','), or
|
||||
whitespace or control characters (ASCII codes 32 or less). Names are
|
||||
case-sensitive, and MUST NOT be longer than 64 characters.
|
||||
|
||||
Requests for assignment of new key-exchange method names must be
|
||||
accompanied by a reference to a standards-track or Informational RFC
|
||||
which describes this method.
|
||||
|
||||
Method name Reference
|
||||
------------ ---------
|
||||
diffie-hellman-group1-sha1 [SSH-TRANS, Section 4.5]
|
||||
|
||||
|
||||
4. Assigned Algorithm Names
|
||||
|
||||
The following identifiers (names) MUST be printable US-ASCII strings,
|
||||
and MUST NOT contain the characters at-sign ('@'), comma (','), or
|
||||
whitespace or control characters (ASCII codes 32 or less). Names are
|
||||
case-sensitive, and MUST NOT be longer than 64 characters.
|
||||
|
||||
Requests for assignment of new algorithm names must be accompanied by
|
||||
a reference to a standards-track or Informational RFC or a reference
|
||||
to published cryptographic literature which describes the algorithm.
|
||||
|
||||
4.1 Encryption Algorithm Names
|
||||
|
||||
Cipher name Reference
|
||||
------------ ---------
|
||||
3des-cbc [SSH-TRANS, Section 4.3]
|
||||
blowfish-cbc [SSH-TRANS, Section 4.3]
|
||||
twofish256-cbc [SSH-TRANS, Section 4.3]
|
||||
twofish-cbc [SSH-TRANS, Section 4.3]
|
||||
twofish192-cbc [SSH-TRANS, Section 4.3]
|
||||
twofish128-cbc [SSH-TRANS, Section 4.3]
|
||||
aes256-cbc [SSH-TRANS, Section 4.3]
|
||||
aes192-cbc [SSH-TRANS, Section 4.3]
|
||||
aes128-cbc [SSH-TRANS, Section 4.3]
|
||||
serpent256-cbc [SSH-TRANS, Section 4.3]
|
||||
serpent192-cbc [SSH-TRANS, Section 4.3]
|
||||
serpent128-cbc [SSH-TRANS, Section 4.3]
|
||||
arcfour [SSH-TRANS, Section 4.3]
|
||||
idea-cbc [SSH-TRANS, Section 4.3]
|
||||
cast128-cbc [SSH-TRANS, Section 4.3]
|
||||
none [SSH-TRANS, Section 4.3]
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 7]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
des-cbc [FIPS-46-3] HISTORIC; See page 4 of [FIPS 46-3]
|
||||
|
||||
|
||||
4.2 MAC Algorithm Names
|
||||
|
||||
|
||||
|
||||
MAC name Reference
|
||||
--------- ---------
|
||||
hmac-sha1 [SSH-TRANS, Section 4.4]
|
||||
hmac-sha1-96 [SSH-TRANS, Section 4.4]
|
||||
hmac-md5 [SSH-TRANS, Section 4.4]
|
||||
hmac-md5-96 [SSH-TRANS, Section 4.4]
|
||||
none [SSH-TRANS, Section 4.4]
|
||||
|
||||
|
||||
4.3 Public Key Algorithm Names
|
||||
|
||||
Algorithm name Reference
|
||||
--------------- ---------
|
||||
ssh-dss [SSH-TRANS, Section 4.6]
|
||||
ssh-rsa [SSH-TRANS, Section 4.6]
|
||||
x509v3-sign-rsa [SSH-TRANS, Section 4.6]
|
||||
x509v3-sign-dss [SSH-TRANS, Section 4.6]
|
||||
spki-sign-rsa [SSH-TRANS, Section 4.6]
|
||||
spki-sign-dss [SSH-TRANS, Section 4.6]
|
||||
pgp-sign-rsa [SSH-TRANS, Section 4.6]
|
||||
pgp-sign-dss [SSH-TRANS, Section 4.6]
|
||||
|
||||
|
||||
4.4 Compression Algorithm Names
|
||||
|
||||
Algorithm name Reference
|
||||
--------------- ---------
|
||||
none [SSH-TRANS, Section 4.2]
|
||||
zlib [SSH-TRANS, Section 4.2]
|
||||
|
||||
References
|
||||
|
||||
[SSH-ARCH] Ylonen, T., "SSH Protocol Architecture", I-D draft-
|
||||
ietf-architecture-14.txt, July 2003.
|
||||
|
||||
[SSH-TRANS] Ylonen, T., "SSH Transport Layer Protocol", I-D
|
||||
draft-ietf-transport-16.txt, July 2003.
|
||||
|
||||
[SSH-USERAUTH] Ylonen, T., "SSH Authentication Protocol", I-D draft-
|
||||
ietf-userauth-17.txt, July 2003.
|
||||
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 8]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
[SSH-CONNECT] Ylonen, T., "SSH Connection Protocol", I-D draft-
|
||||
ietf-connect-17.txt, July 2003.
|
||||
|
||||
[SSH-NUMBERS] Lehtinen, S. and D. Moffat, "SSH Protocol Assigned
|
||||
Numbers", I-D draft-ietf-secsh-assignednumbers-
|
||||
03.txt, July 2003.
|
||||
|
||||
[FIPS-46-3] U.S. Dept. of Commerce, ., "FIPS PUB 46-3, Data
|
||||
Encryption Standard (DES)", October 1999.
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Sami Lehtinen
|
||||
SSH Communications Security Corp
|
||||
Fredrikinkatu 42
|
||||
HELSINKI FIN-00100
|
||||
Finland
|
||||
|
||||
EMail: sjl@ssh.com
|
||||
|
||||
|
||||
Darren J Moffat
|
||||
Sun Microsystems
|
||||
901 San Antonio Road
|
||||
Palo Alto 94303
|
||||
USA
|
||||
|
||||
EMail: Darren.Moffat@Sun.COM
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 9]
|
||||
|
||||
Internet-Draft SSH Protocol Assigned Numbers August 2003
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is currently provided by the
|
||||
Internet Society.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Lehtinen & Moffat Expires February 13, 2004 [Page 10]
|
||||
|
||||
|
366
doc/draft-ietf-secsh-auth-kbdinteract-05-cleaned.txt
Обычный файл
366
doc/draft-ietf-secsh-auth-kbdinteract-05-cleaned.txt
Обычный файл
@ -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
Обычный файл
619
doc/draft-ietf-secsh-auth-kbdinteract-05.txt
Обычный файл
@ -0,0 +1,619 @@
|
||||
|
||||
|
||||
|
||||
Network Working Group F. Cusack
|
||||
INTERNET-DRAFT Google, Inc.
|
||||
Expires November 1, 2003 M. Forssen
|
||||
Appgate AB
|
||||
May 1, 2003
|
||||
|
||||
|
||||
|
||||
|
||||
Generic Message Exchange Authentication For SSH
|
||||
<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
Обычный файл
394
doc/draft-ietf-secsh-break-00.txt
Обычный файл
@ -0,0 +1,394 @@
|
||||
|
||||
|
||||
|
||||
Secure Shell Working Group J. Galbraith
|
||||
Internet-Draft VanDyke Software
|
||||
Expires: September 17, 2003 P. Remaker
|
||||
Cisco Systems, Inc
|
||||
March 19, 2003
|
||||
|
||||
|
||||
Session Channel Break Extension
|
||||
draft-ietf-secsh-break-00.txt
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that other
|
||||
groups may also distribute working documents as Internet-Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at http://
|
||||
www.ietf.org/ietf/1id-abstracts.txt.
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
This Internet-Draft will expire on September 17, 2003.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
Abstract
|
||||
|
||||
The Break Extension provides a way to send a break signal during a
|
||||
SSH terminal session.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Remaker Expires September 17, 2003 [Page 1]
|
||||
|
||||
Internet-Draft Session Channel Break Extension March 2003
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
2. The Break Request . . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
References . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
Intellectual Property and Copyright Statements . . . . . . . . . 6
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Remaker Expires September 17, 2003 [Page 2]
|
||||
|
||||
Internet-Draft Session Channel Break Extension March 2003
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
The SSH session channel provides a mechanism for the client-user to
|
||||
interactively enter commands and receive output from a remote host
|
||||
while taking advantage of the SSH transport's privacy and integrity
|
||||
features.
|
||||
|
||||
A common application of the telnet protocol is the "Console Server"
|
||||
whereby a telnet NVT can be connected to a physical RS-232/V.24
|
||||
asynchronous port, allowing the telnet NVT to appear as a locally
|
||||
attached terminal to that port, and allowing that port to appear as a
|
||||
network addressable device. A number of major computer equipment
|
||||
vendors provide high level administrative functions through an
|
||||
asynchronous serial port and generally expect the attached terminal
|
||||
to be capable of send a BREAK signal, which is defined as the TxD
|
||||
signal being held in a SPACE state for a time greater than a whole
|
||||
character time, typically interpreted as 250 to 500 ms.
|
||||
|
||||
The telnet protocolprovides a means to send a "BREAK" signal, which
|
||||
is defined as a "a signal outside the USASCII set which is currently
|
||||
given local meaning within many systems." [1] Console Server vendors
|
||||
interpret the TELNET break signal as a physical break signal, which
|
||||
can then allow access to the full range of administartive functions
|
||||
available on an asynchronous serial console port.
|
||||
|
||||
The lack of a similar facility in the SSH session channel has forced
|
||||
users to continue the use of telnet for the "Console Server"
|
||||
function.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Remaker Expires September 17, 2003 [Page 3]
|
||||
|
||||
Internet-Draft Session Channel Break Extension March 2003
|
||||
|
||||
|
||||
2. The Break Request
|
||||
|
||||
The following following channel specific request can be sent to
|
||||
request that the remote host perform a break operation.
|
||||
|
||||
byte SSH_MSG_CHANNEL_REQUEST
|
||||
uint32 recipient channel
|
||||
string "break"
|
||||
boolean want_reply
|
||||
uint32 break-length in milliseconds
|
||||
|
||||
If the break length cannot be controlled by the application receiving
|
||||
this request, the break length parameter SHOULD be ignored and the
|
||||
default break signal length of the chipset or underlying chipset
|
||||
driver SHOULD be sent.
|
||||
|
||||
If the application can control the break-length, the following
|
||||
suggestions are made reagarding break duration. If a break duration
|
||||
request of greater than 3000ms is received, it SHOULD be processed as
|
||||
a 3000ms break, in order to an unreasonably long break request
|
||||
causing the port to become unavailable for as long as 47 days while
|
||||
executing the break. Applications that require a longer break may
|
||||
choose to ignore this requirement. If break duration request of
|
||||
less than 500ms, is requested a break of 500ms SHOULD be sent since
|
||||
most devices will recognize a break of that length. In the event
|
||||
that an application needs a shorter break, this can be ignored. If
|
||||
the break-length parameter is 0, the break SHOULD be sent as 500ms or
|
||||
the default break signal length of the chipset or underlying chipset
|
||||
driver .
|
||||
|
||||
If the want_reply boolean is set, the server MUST reply using
|
||||
SSH_MSG_CHANNEL_SUCCESS or SSH_MSG_CHANNEL_FAILURE [4] messages. If
|
||||
a break of any kind was preformed, SSH_MSG_CHANNEL_SUCCESS MUST be
|
||||
sent. If no break was preformed, SSH_MSG_CHANNEL_FAILURE MUST be
|
||||
sent.
|
||||
|
||||
This operation SHOULD be support by most general purpose SSH clients.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Remaker Expires September 17, 2003 [Page 4]
|
||||
|
||||
Internet-Draft Session Channel Break Extension March 2003
|
||||
|
||||
|
||||
References
|
||||
|
||||
[1] Postel, J. and J. Reynolds, "Telnet Protocol Specification", STD
|
||||
8, RFC 854, May 1983.
|
||||
|
||||
[2] Rinne, T., Ylonen, T., Kivinen, T. and S. Lehtinen, "SSH
|
||||
Protocol Architecture", draft-ietf-secsh-architecture-13 (work
|
||||
in progress), September 2002.
|
||||
|
||||
[3] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.
|
||||
Lehtinen, "SSH Transport Layer Protocol",
|
||||
draft-ietf-secsh-transport-15 (work in progress), September
|
||||
2002.
|
||||
|
||||
[4] Rinne, T., Ylonen, T., Kivinen, T. and S. Lehtinen, "SSH
|
||||
Connection Protocol", draft-ietf-secsh-connect-16 (work in
|
||||
progress), September 2002.
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Joseph Galbraith
|
||||
VanDyke Software
|
||||
4848 Tramway Ridge Blvd
|
||||
Suite 101
|
||||
Albuquerque, NM 87111
|
||||
US
|
||||
|
||||
Phone: +1 505 332 5700
|
||||
EMail: galb-list@vandyke.com
|
||||
|
||||
|
||||
Phillip Remaker
|
||||
Cisco Systems, Inc
|
||||
170 West Tasman Drive
|
||||
San Jose, CA 95120
|
||||
US
|
||||
|
||||
EMail: remaker@cisco.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Remaker Expires September 17, 2003 [Page 5]
|
||||
|
||||
Internet-Draft Session Channel Break Extension March 2003
|
||||
|
||||
|
||||
Intellectual Property Statement
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
intellectual property or other rights that might be claimed to
|
||||
pertain to the implementation or use of the technology described in
|
||||
this document or the extent to which any license under such rights
|
||||
might or might not be available; neither does it represent that it
|
||||
has made any effort to identify any such rights. Information on the
|
||||
IETF's procedures with respect to rights in standards-track and
|
||||
standards-related documentation can be found in BCP-11. Copies of
|
||||
claims of rights made available for publication and any assurances of
|
||||
licenses to be made available, or the result of an attempt made to
|
||||
obtain a general license or permission for the use of such
|
||||
proprietary rights by implementors or users of this specification can
|
||||
be obtained from the IETF Secretariat.
|
||||
|
||||
The IETF invites any interested party to bring to its attention any
|
||||
copyrights, patents or patent applications, or other proprietary
|
||||
rights which may cover technology that may be required to practice
|
||||
this standard. Please address the information to the IETF Executive
|
||||
Director.
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assignees.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
|
||||
|
||||
|
||||
Galbraith & Remaker Expires September 17, 2003 [Page 6]
|
||||
|
||||
Internet-Draft Session Channel Break Extension March 2003
|
||||
|
||||
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is currently provided by the
|
||||
Internet Society.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Remaker Expires September 17, 2003 [Page 7]
|
||||
|
||||
|
1232
doc/draft-ietf-secsh-connect-17.txt
Обычный файл
1232
doc/draft-ietf-secsh-connect-17.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
451
doc/draft-ietf-secsh-dh-group-exchange-04.txt
Обычный файл
451
doc/draft-ietf-secsh-dh-group-exchange-04.txt
Обычный файл
@ -0,0 +1,451 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group Markus Friedl
|
||||
INTERNET-DRAFT Niels Provos
|
||||
Expires in six months William A. Simpson
|
||||
July 2003
|
||||
|
||||
|
||||
Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol
|
||||
draft-ietf-secsh-dh-group-exchange-04.txt
|
||||
|
||||
|
||||
1. Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as Internet-
|
||||
Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six
|
||||
months and may be updated, replaced, or obsoleted by other docu-
|
||||
ments at any time. It is inappropriate to use Internet- Drafts as
|
||||
reference material or to cite them other than as "work in
|
||||
progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at
|
||||
http://www.ietf.org/ietf/1id-abstracts.txt
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
2. Copyright Notice
|
||||
|
||||
Copyright (C) 2000-2003 by Markus Friedl, Niels Provos and William
|
||||
A. Simpson.
|
||||
|
||||
3. Abstract
|
||||
|
||||
This memo describes a new key exchange method for the SSH protocol.
|
||||
It allows the SSH server to propose to the client new groups on
|
||||
which to perform the Diffie-Hellman key exchange. The proposed
|
||||
groups need not be fixed and can change with time.
|
||||
|
||||
4. Overview and Rational
|
||||
|
||||
SSH [4,5,6,7] is a a very common protocol for secure remote login
|
||||
on the Internet. Currently, SSH performs the initial key exchange
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 1]
|
||||
|
||||
INTERNET DRAFT July 2003
|
||||
|
||||
|
||||
using the "diffie-hellman-group1-sha1" method. This method pre-
|
||||
scribes a fixed group on which all operations are performed.
|
||||
|
||||
The Diffie-Hellman key exchange provides a shared secret that can
|
||||
not be determined by either party alone. In SSH, the key exchange
|
||||
is signed with the host key to provide host authentication.
|
||||
|
||||
The security of the Diffie-Hellman key exchange is based on the
|
||||
difficulty of solving the Discrete Logarithm Problem (DLP). Since
|
||||
we expect that the SSH protocol will be in use for many years in
|
||||
the future, we fear that extensive precomputation and more effi-
|
||||
cient algorithms to compute the discrete logarithm over a fixed
|
||||
group might pose a security threat to the SSH protocol.
|
||||
|
||||
The ability to propose new groups will reduce the incentive to use
|
||||
precomputation for more efficient calculation of the discrete loga-
|
||||
rithm. The server can constantly compute new groups in the back-
|
||||
ground.
|
||||
|
||||
5. Diffie-Hellman Group and Key Exchange
|
||||
|
||||
The server keeps a list of safe primes and corresponding generators
|
||||
that it can select from. A prime p is safe, if p = 2q + 1, and q
|
||||
is prime. New primes can be generated in the background.
|
||||
|
||||
The generator g should be chosen such that the order of the gener-
|
||||
ated subgroup does not factor into small primes, i.e., with p = 2q
|
||||
+ 1, the order has to be either q or p - 1. If the order is p - 1,
|
||||
then the exponents generate all possible public-values, evenly dis-
|
||||
tributed throughout the range of the modulus p, without cycling
|
||||
through a smaller subset. Such a generator is called a "primitive
|
||||
root" (which is trivial to find when p is "safe").
|
||||
|
||||
Implementation Notes:
|
||||
|
||||
One useful technique is to select the generator, and then
|
||||
limit the modulus selection sieve to primes with that genera-
|
||||
tor:
|
||||
|
||||
2 when p (mod 24) = 11.
|
||||
5 when p (mod 10) = 3 or 7.
|
||||
|
||||
It is recommended to use 2 as generator, because it improves
|
||||
efficiency in multiplication performance. It is usable even
|
||||
when it is not a primitive root, as it still covers half of
|
||||
the space of possible residues.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 2]
|
||||
|
||||
INTERNET DRAFT July 2003
|
||||
|
||||
|
||||
The client requests a modulus from the server indicating the pre-
|
||||
ferred size. In the following description (C is the client, S is
|
||||
the server; the modulus p is a large safe prime and g is a genera-
|
||||
tor for a subgroup of GF(p); min is the minimal size of p in bits
|
||||
that is acceptable to the client; n is the size of the modulus p in
|
||||
bits that the client would like to receive from the server; max is
|
||||
the maximal size of p in bits that the client can accept; V_S is
|
||||
S's version string; V_C is C's version string; K_S is S's public
|
||||
host key; I_C is C's KEXINIT message and I_S S's KEXINIT message
|
||||
which have been exchanged before this part begins):
|
||||
|
||||
1. C sends "min || n || max" to S, indicating the minimal accept-
|
||||
able group size, the preferred size of the group and the maxi-
|
||||
mal group size in bits the client will accept.
|
||||
|
||||
2. S finds a group that best matches the client's request, and
|
||||
sends "p || g" to C.
|
||||
|
||||
3. C generates a random number x (1 < x < (p-1)/2). It computes e
|
||||
= g^x mod p, and sends "e" to S.
|
||||
|
||||
4. S generates a random number y (0 < y < (p-1)/2) and computes f
|
||||
= g^y mod p. S receives "e". It computes K = e^y mod p, H =
|
||||
hash(V_C || V_S || I_C || I_S || K_S || min || n || max || p
|
||||
|| g || e || f || K) (these elements are encoded according to
|
||||
their types; see below), and signature s on H with its private
|
||||
host key. S sends "K_S || f || s" to C. The signing opera-
|
||||
tion may involve a second hashing operation.
|
||||
|
||||
Implementation Notes:
|
||||
|
||||
To increase the speed of the key exchange, both client
|
||||
and server may reduce the size of their private expo-
|
||||
nents. It should be at least twice as long as the key
|
||||
material that is generated from the shared secret. For
|
||||
more details see the paper by van Oorschot and Wiener
|
||||
[1].
|
||||
|
||||
5. C verifies that K_S really is the host key for S (e.g. using
|
||||
certificates or a local database). C is also allowed to
|
||||
accept the key without verification; however, doing so will
|
||||
render the protocol insecure against active attacks (but may
|
||||
be desirable for practical reasons in the short term in many
|
||||
environments). C then computes K = f^x mod p, H = hash(V_C ||
|
||||
V_S || I_C || I_S || K_S || min || n || max || p || g || e ||
|
||||
f || K), and verifies the signature s on H.
|
||||
|
||||
Servers and clients SHOULD support groups with a modulus
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 3]
|
||||
|
||||
INTERNET DRAFT July 2003
|
||||
|
||||
|
||||
length of k bits, where 1024 <= k <= 8192. The recommended
|
||||
values for min and max are 1024 and 8192 respectively.
|
||||
|
||||
Either side MUST NOT send or accept e or f values that are not
|
||||
in the range [1, p-1]. If this condition is violated, the key
|
||||
exchange fails. To prevent confinement attacks, they MUST
|
||||
accept the shared secret K only if 1 < K < p - 1.
|
||||
|
||||
|
||||
The server should return the smallest group it knows that is larger
|
||||
than the size the client requested. If the server does not know a
|
||||
group that is larger than the client request, then it SHOULD return
|
||||
the largest group it knows. In all cases, the size of the returned
|
||||
group SHOULD be at least 1024 bits.
|
||||
|
||||
This is implemented with the following messages. The hash algo-
|
||||
rithm for computing the exchange hash is defined by the method
|
||||
name, and is called HASH. The public key algorithm for signing is
|
||||
negotiated with the KEXINIT messages.
|
||||
|
||||
First, the client sends:
|
||||
byte SSH_MSG_KEY_DH_GEX_REQUEST
|
||||
uint32 min, minimal size in bits of an acceptable group
|
||||
uint32 n, preferred size in bits of the group the server should send
|
||||
uint32 max, maximal size in bits of an acceptable group
|
||||
|
||||
The server responds with
|
||||
byte SSH_MSG_KEX_DH_GEX_GROUP
|
||||
mpint p, safe prime
|
||||
mpint g, generator for subgroup in GF(p)
|
||||
|
||||
The client responds with:
|
||||
byte SSH_MSG_KEX_DH_GEX_INIT
|
||||
mpint e
|
||||
|
||||
The server responds with:
|
||||
byte SSH_MSG_KEX_DH_GEX_REPLY
|
||||
string server public host key and certificates (K_S)
|
||||
mpint f
|
||||
string signature of H
|
||||
|
||||
The hash H is computed as the HASH hash of the concatenation of the
|
||||
following:
|
||||
string V_C, the client's version string (CR and NL excluded)
|
||||
string V_S, the server's version string (CR and NL excluded)
|
||||
string I_C, the payload of the client's SSH_MSG_KEXINIT
|
||||
string I_S, the payload of the server's SSH_MSG_KEXINIT
|
||||
string K_S, the host key
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 4]
|
||||
|
||||
INTERNET DRAFT July 2003
|
||||
|
||||
|
||||
uint32 min, minimal size in bits of an acceptable group
|
||||
uint32 n, preferred size in bits of the group the server should send
|
||||
uint32 max, maximal size in bits of an acceptable group
|
||||
mpint p, safe prime
|
||||
mpint g, generator for subgroup
|
||||
mpint e, exchange value sent by the client
|
||||
mpint f, exchange value sent by the server
|
||||
mpint K, the shared secret
|
||||
|
||||
This value is called the exchange hash, and it is used to authenti-
|
||||
cate the key exchange.
|
||||
|
||||
|
||||
6. diffie-hellman-group-exchange-sha1
|
||||
|
||||
The "diffie-hellman-group-exchange-sha1" method specifies Diffie-
|
||||
Hellman Group and Key Exchange with SHA-1 as HASH.
|
||||
|
||||
7. Summary of Message numbers
|
||||
|
||||
The following message numbers have been defined in this document.
|
||||
|
||||
#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||
#define SSH_MSG_KEX_DH_GEX_REQUEST 34
|
||||
#define SSH_MSG_KEX_DH_GEX_GROUP 31
|
||||
#define SSH_MSG_KEX_DH_GEX_INIT 32
|
||||
#define SSH_MSG_KEX_DH_GEX_REPLY 33
|
||||
|
||||
SSH_MSG_KEX_DH_GEX_REQUEST_OLD is used for backwards compatibility.
|
||||
Instead of sending "min || n || max", the client only sends "n".
|
||||
Additionally, the hash is calculated using only "n" instead of "min
|
||||
|| n || max".
|
||||
|
||||
The numbers 30-49 are key exchange specific and may be redefined by
|
||||
other kex methods.
|
||||
|
||||
8. Security Considerations
|
||||
|
||||
This protocol aims to be simple and uses only well understood prim-
|
||||
itives. This encourages acceptance by the community and allows for
|
||||
ease of implementation, which hopefully leads to a more secure sys-
|
||||
tem.
|
||||
|
||||
The use of multiple moduli inhibits a determined attacker from pre-
|
||||
calculating moduli exchange values, and discourages dedication of
|
||||
resources for analysis of any particular modulus.
|
||||
|
||||
It is important to employ only safe primes as moduli. Van Oorshot
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 5]
|
||||
|
||||
INTERNET DRAFT July 2003
|
||||
|
||||
|
||||
and Wiener note that using short private exponents with a random
|
||||
prime modulus p makes the computation of the discrete logarithm
|
||||
easy [1]. However, they also state that this problem does not
|
||||
apply to safe primes.
|
||||
|
||||
The least significant bit of the private exponent can be recovered,
|
||||
when the modulus is a safe prime [2]. However, this is not a prob-
|
||||
lem, if the size of the private exponent is big enough. Related to
|
||||
this, Waldvogel and Massey note: When private exponents are chosen
|
||||
independently and uniformly at random from {0,...,p-2}, the key
|
||||
entropy is less than 2 bits away from the maximum, lg(p-1) [3].
|
||||
|
||||
9. Acknowledgments
|
||||
|
||||
The document is derived in part from "SSH Transport Layer Protocol"
|
||||
by T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen.
|
||||
|
||||
Markku-Juhani Saarinen pointed out that the least significant bit
|
||||
of the private exponent can be recovered efficiently when using
|
||||
safe primes and a subgroup with an order divisible by two.
|
||||
|
||||
Bodo Moeller suggested that the server send only one group, reduc-
|
||||
ing the complexity of the implementation and the amount of data
|
||||
that needs to be exchanged between client and server.
|
||||
|
||||
10. Bibliography
|
||||
|
||||
|
||||
10.1. Informative References
|
||||
|
||||
|
||||
[1] P. C. van Oorschot and M. J. Wiener, On Diffie-Hellman key
|
||||
agreement with short exponents, In Advances in Cryptology -
|
||||
EUROCRYPT'96, LNCS 1070, Springer-Verlag, 1996, pp.332-343.
|
||||
|
||||
[2] Alfred J. Menezes, Paul C. van Oorschot, and Scott A. Van-
|
||||
stone. Handbook of Applied Cryptography. CRC Press, 1996.
|
||||
|
||||
[3] C. P. Waldvogel and J. L. Massey, The probability distribution
|
||||
of the Diffie-Hellman key, in Proceedings of AUSCRYPT 92, LNCS
|
||||
718, Springer- Verlag, 1993, pp. 492-504.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 6]
|
||||
|
||||
INTERNET DRAFT July 2003
|
||||
|
||||
|
||||
10.2. Normative References
|
||||
|
||||
|
||||
[4] Ylonen, T., et al: "SSH Protocol Architecture", Internet-
|
||||
Draft, draft-secsh-architecture-07.txt
|
||||
|
||||
[5] Ylonen, T., et al: "SSH Transport Layer Protocol", Internet-
|
||||
Draft, draft-ietf-secsh-transport-09.txt
|
||||
|
||||
[6] Ylonen, T., et al: "SSH Authentication Protocol", Internet-
|
||||
Draft, draft-ietf-secsh-userauth-09.txt
|
||||
|
||||
[7] Ylonen, T., et al: "SSH Connection Protocol", Internet-Draft,
|
||||
draft-ietf-secsh-connect-09.txt
|
||||
|
||||
|
||||
|
||||
11. Appendix A: Generation of safe primes
|
||||
|
||||
The Handbook of Applied Cryptography [2] lists the following algo-
|
||||
rithm to generate a k-bit safe prime p. It has been modified so
|
||||
that 2 is a generator for the multiplicative group mod p.
|
||||
|
||||
1. Do the following:
|
||||
1.1 Select a random (k-1)-bit prime q, so that q mod 12 = 5.
|
||||
1.2 Compute p := 2q + 1, and test whether p is prime, (using, e.g.
|
||||
trial division and the Rabin-Miller test.)
|
||||
Repeat until p is prime.
|
||||
|
||||
If an implementation uses the OpenSSL libraries, a group consisting
|
||||
of a 1024-bit safe prime and 2 as generator can be created as fol-
|
||||
lows:
|
||||
|
||||
DH *d = NULL;
|
||||
d = DH_generate_parameters(1024, DH_GENERATOR_2, NULL, NULL);
|
||||
BN_print_fp(stdout, d->p);
|
||||
|
||||
The order of the subgroup generated by 2 is q = p - 1.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 7]
|
||||
|
||||
INTERNET DRAFT July 2003
|
||||
|
||||
|
||||
12. Author's Address
|
||||
|
||||
Markus Friedl
|
||||
Ganghoferstr. 7
|
||||
80339 Munich
|
||||
Germany
|
||||
|
||||
Email: markus@openbsd.org
|
||||
|
||||
Niels Provos
|
||||
Center for Information Technology Integration
|
||||
535 W. William Street
|
||||
Ann Arbor, MI, 48103
|
||||
|
||||
Phone: (734) 764-5207
|
||||
Email: provos@citi.umich.edu
|
||||
|
||||
William Allen Simpson
|
||||
DayDreamer
|
||||
Computer Systems Consulting Services
|
||||
1384 Fontaine
|
||||
Madion Heights, Michigan 48071
|
||||
|
||||
Email: wsimpson@greendragon.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Friedl/Provos/Simpson expires in six months [Page 8]
|
||||
|
616
doc/draft-ietf-secsh-dns-04.txt
Обычный файл
616
doc/draft-ietf-secsh-dns-04.txt
Обычный файл
@ -0,0 +1,616 @@
|
||||
|
||||
|
||||
Secure Shell Working Group J. Schlyter
|
||||
Internet-Draft Carlstedt Research &
|
||||
Expires: October 1, 2003 Technology
|
||||
W. Griffin
|
||||
Network Associates Laboratories
|
||||
April 2, 2003
|
||||
|
||||
|
||||
Using DNS to securely publish SSH key fingerprints
|
||||
draft-ietf-secsh-dns-04.txt
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that other
|
||||
groups may also distribute working documents as Internet-Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at http://
|
||||
www.ietf.org/ietf/1id-abstracts.txt.
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
This Internet-Draft will expire on October 1, 2003.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes a method to verify SSH host keys using
|
||||
DNSSEC. The document defines a new DNS resource record that contains
|
||||
a standard SSH key fingerprint.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 1]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
2. SSH Host Key Verification . . . . . . . . . . . . . . . . . 3
|
||||
2.1 Method . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
2.2 Implementation Notes . . . . . . . . . . . . . . . . . . . . 3
|
||||
2.3 Fingerprint Matching . . . . . . . . . . . . . . . . . . . . 4
|
||||
2.4 Authentication . . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
3. The SSHFP Resource Record . . . . . . . . . . . . . . . . . 4
|
||||
3.1 The SSHFP RDATA Format . . . . . . . . . . . . . . . . . . . 4
|
||||
3.1.1 Algorithm Number Specification . . . . . . . . . . . . . . . 5
|
||||
3.1.2 Fingerprint Type Specification . . . . . . . . . . . . . . . 5
|
||||
3.1.3 Fingerprint . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
3.2 Presentation Format of the SSHFP RR . . . . . . . . . . . . 6
|
||||
4. Security Considerations . . . . . . . . . . . . . . . . . . 6
|
||||
5. IANA Considerations . . . . . . . . . . . . . . . . . . . . 7
|
||||
Normative References . . . . . . . . . . . . . . . . . . . . 8
|
||||
Informational References . . . . . . . . . . . . . . . . . . 8
|
||||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 8
|
||||
A. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 9
|
||||
Intellectual Property and Copyright Statements . . . . . . . 10
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 2]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
The SSH [5] protocol provides secure remote login and other secure
|
||||
network services over an insecure network. The security of the
|
||||
connection relies on the server authenticating itself to the client.
|
||||
|
||||
Server authentication is normally done by presenting the fingerprint
|
||||
of an unknown public key to the user for verification. If the user
|
||||
decides the fingerprint is correct and accepts the key, the key is
|
||||
saved locally and used for verification for all following
|
||||
connections. While some security-conscious users verify the
|
||||
fingerprint out-of-band before accepting the key, many users blindly
|
||||
accepts the presented key.
|
||||
|
||||
The method described here can provide out-of-band verification by
|
||||
looking up a fingerprint of the server public key in the DNS [1][2]
|
||||
and using DNSSEC [4] to verify the lookup.
|
||||
|
||||
In order to distribute the fingerprint using DNS, this document
|
||||
defines a new DNS resource record to carry the fingerprint.
|
||||
|
||||
Basic understanding of the DNS system [1][2] and the DNS security
|
||||
extensions [4] is assumed by this document.
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [3].
|
||||
|
||||
2. SSH Host Key Verification
|
||||
|
||||
2.1 Method
|
||||
|
||||
Upon connection to a SSH server, the SSH client MAY look up the SSHFP
|
||||
resource record(s) for the host it is connecting to. If the
|
||||
algorithm and fingerprint of the key received from the SSH server
|
||||
matches the algorithm and fingerprint of one of the SSHFP resource
|
||||
record(s) returned from DNS, the client MAY accept the identity of
|
||||
the server.
|
||||
|
||||
2.2 Implementation Notes
|
||||
|
||||
Client implementors SHOULD provide a configurable policy used to
|
||||
select the order of methods used to verify a host key. This document
|
||||
defines one method: Fingerprint storage in DNS. Another method
|
||||
defined in the SSH Architecture [5] uses local files to store keys
|
||||
for comparison. Other methods that could be defined in the future
|
||||
might include storing fingerprints in LDAP or other databases. A
|
||||
configurable policy will allow administrators to determine which
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 3]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
methods they want to use and in what order the methods should be
|
||||
prioritized. This will allow administrators to determine how much
|
||||
trust they want to place in the different methods.
|
||||
|
||||
One specific scenario for having a configurable policy is where
|
||||
clients do not use fully qualified host names to connect to servers.
|
||||
In this scenario, the implementation SHOULD verify the host key
|
||||
against a local database before verifying the key via the fingerprint
|
||||
returned from DNS. This would help prevent an attacker from injecting
|
||||
a DNS search path into the local resolver and forcing the client to
|
||||
connect to a different host.
|
||||
|
||||
2.3 Fingerprint Matching
|
||||
|
||||
The public key and the SSHFP resource record are matched together by
|
||||
comparing algorithm number and fingerprint.
|
||||
|
||||
The public key algorithm and the SSHFP algorithm number MUST
|
||||
match.
|
||||
|
||||
A message digest of the public key, using the message digest
|
||||
algorithm specified in the SSHFP fingerprint type, MUST match the
|
||||
SSH FP fingerprint.
|
||||
|
||||
|
||||
2.4 Authentication
|
||||
|
||||
A public key verified using this method MUST only be trusted if the
|
||||
SSHFP resource record (RR) used for verification was authenticated by
|
||||
a trusted SIG RR.
|
||||
|
||||
Clients that do not validate the DNSSEC signatures themselves MUST
|
||||
use a secure transport, e.g. TSIG [8], SIG(0) [9] or IPsec [7],
|
||||
between themselves and the entity performing the signature
|
||||
validation.
|
||||
|
||||
3. The SSHFP Resource Record
|
||||
|
||||
The SSHFP resource record (RR) is used to store a fingerprint of a
|
||||
SSH public host key that is associated with a Domain Name System
|
||||
(DNS) name.
|
||||
|
||||
The RR type code for the SSHFP RR is TBA.
|
||||
|
||||
3.1 The SSHFP RDATA Format
|
||||
|
||||
The RDATA for a SSHFP RR consists of an algorithm number, fingerprint
|
||||
type and the fingerprint of the public host key.
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 4]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| algorithm | fp type | /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /
|
||||
/ /
|
||||
/ fingerprint /
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
3.1.1 Algorithm Number Specification
|
||||
|
||||
This algorithm number octet describes the algorithm of the public
|
||||
key. The following values are assigned:
|
||||
|
||||
Value Algorithm name
|
||||
----- --------------
|
||||
0 reserved
|
||||
1 RSA
|
||||
2 DSS
|
||||
|
||||
Reserving other types requires IETF consensus.
|
||||
|
||||
3.1.2 Fingerprint Type Specification
|
||||
|
||||
The fingerprint type octet describes the message-digest algorithm
|
||||
used to calculate the fingerprint of the public key. The following
|
||||
values are assigned:
|
||||
|
||||
Value Fingerprint type
|
||||
----- ----------------
|
||||
0 reserved
|
||||
1 SHA-1
|
||||
|
||||
Reserving other types requires IETF consensus. For interoperability
|
||||
reasons, as few fingerprint types as possible should be reserved.
|
||||
The only reason to reserve additional types is to increase security.
|
||||
|
||||
3.1.3 Fingerprint
|
||||
|
||||
The fingerprint is calculated over the public key blob as described
|
||||
in [6].
|
||||
|
||||
The message-digest algorithm is presumed to produce an opaque octet
|
||||
string output which is placed as-is in the RDATA fingerprint field.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 5]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
3.2 Presentation Format of the SSHFP RR
|
||||
|
||||
The presentation format of the SSHFP resource record consists of two
|
||||
numbers (algorithm and fingerprint type) followed by the fingerprint
|
||||
itself presented in hex, e.g:
|
||||
|
||||
host.example. SSHFP 2 1 123456789abcdef67890123456789abcdef67890
|
||||
|
||||
|
||||
4. Security Considerations
|
||||
|
||||
Currently, the amount of trust a user can realistically place in a
|
||||
server key is proportional to the amount of attention paid to
|
||||
verifying that the public key presented actually corresponds to the
|
||||
private key of the server. If a user accepts a key without verifying
|
||||
the fingerprint with something learned through a secured channel, the
|
||||
connection is vulnerable to a man-in-the-middle attack.
|
||||
|
||||
The approach suggested here shifts the burden of key checking from
|
||||
each user of a machine to the key checking performed by the
|
||||
administrator of the DNS recursive server used to resolve the host
|
||||
information. Hopefully, by reducing the number of times that keys
|
||||
need to be verified by hand, each verification is performed more
|
||||
completely. Furthermore, by requiring an administrator do the
|
||||
checking, the result may be more reliable than placing this task in
|
||||
the hands of an application user.
|
||||
|
||||
The overall security of using SSHFP for SSH host key verification is
|
||||
dependent on detailed aspects of how verification is done in SSH
|
||||
implementations. One such aspect is in which order fingerprints are
|
||||
looked up (e.g. first checking local file and then SSHFP). We note
|
||||
that in addition to protecting the first-time transfer of host keys,
|
||||
SSHFP can optionally be used for stronger host key protection.
|
||||
|
||||
If SSHFP is checked first, new SSH host keys may be distributed by
|
||||
replacing the corresponding SSHFP in DNS.
|
||||
|
||||
If SSH host key verification can be configured to require SSHFP,
|
||||
we can implement SSH host key revocation by removing the
|
||||
corresponding SSHFP from DNS.
|
||||
|
||||
As stated in Section 2.2, we recommend that SSH implementors provide
|
||||
a policy mechanism to control the order of methods used for host key
|
||||
verification. One specific scenario for having a configurable policy
|
||||
is where clients use unqualified host names to connect to servers. In
|
||||
this case, we recommend that SSH implementations check the host key
|
||||
against a local database before verifying the key via the fingerprint
|
||||
returned from DNS. This would help prevent an attacker from injecting
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 6]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
a DNS search path into the local resolver and forcing the client to
|
||||
connect to a different host.
|
||||
|
||||
A different approach to solve the DNS search path issue would be for
|
||||
clients to use a trusted DNS search path, i.e., one not acquired
|
||||
through DHCP or other autoconfiguration mechanisms. Since there is no
|
||||
way with current DNS lookup APIs to tell whether a search path is
|
||||
from a trusted source, the entire client system would need to be
|
||||
configured with this trusted DNS search path.
|
||||
|
||||
Another dependency is on the implementation of DNSSEC itself. As
|
||||
stated in Section 2.4, we mandate the use of secure methods for
|
||||
lookup and that SSHFP RRs are authenticated by trusted SIG RRs. This
|
||||
is especially important if SSHFP is to be used as a basis for host
|
||||
key rollover and/or revocation, as described above.
|
||||
|
||||
Since DNSSEC only protects the integrity of the host key fingerprint
|
||||
after it is signed by the DNS zone administrator, the fingerprint
|
||||
must be transferred securely from the SSH host administrator to the
|
||||
DNS zone administrator. This could be done manually between the
|
||||
administrators or automatically using secure DNS dynamic update [10]
|
||||
between the SSH server and the nameserver. We note that this is no
|
||||
different from other key enrollment situations, e.g. a client sending
|
||||
a certificate request to a certificate authority for signing.
|
||||
|
||||
5. IANA Considerations
|
||||
|
||||
IANA needs to allocate a RR type code for SSHFP from the standard RR
|
||||
type space (type 44 requested).
|
||||
|
||||
IANA needs to open a new registry for the SSHFP RR type for public
|
||||
key algorithms. Defined types are:
|
||||
|
||||
0 is reserved
|
||||
1 is RSA
|
||||
2 is DSA
|
||||
|
||||
Adding new reservations requires IETF consensus.
|
||||
|
||||
IANA needs to open a new registry for the SSHFP RR type for
|
||||
fingerprint types. Defined types are:
|
||||
|
||||
0 is reserved
|
||||
1 is SHA-1
|
||||
|
||||
Adding new reservations requires IETF consensus.
|
||||
|
||||
Normative References
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 7]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
[1] Mockapetris, P., "Domain names - concepts and facilities", STD
|
||||
13, RFC 1034, November 1987.
|
||||
|
||||
[2] Mockapetris, P., "Domain names - implementation and
|
||||
specification", STD 13, RFC 1035, November 1987.
|
||||
|
||||
[3] Bradner, S., "Key words for use in RFCs to Indicate Requirement
|
||||
Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[4] Eastlake, D., "Domain Name System Security Extensions", RFC
|
||||
2535, March 1999.
|
||||
|
||||
[5] Rinne, T., Ylonen, T., Kivinen, T. and S. Lehtinen, "SSH
|
||||
Protocol Architecture", draft-ietf-secsh-architecture-13 (work
|
||||
in progress), September 2002.
|
||||
|
||||
[6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.
|
||||
Lehtinen, "SSH Transport Layer Protocol",
|
||||
draft-ietf-secsh-transport-15 (work in progress), September
|
||||
2002.
|
||||
|
||||
Informational References
|
||||
|
||||
[7] Thayer, R., Doraswamy, N. and R. Glenn, "IP Security Document
|
||||
Roadmap", RFC 2411, November 1998.
|
||||
|
||||
[8] Vixie, P., Gudmundsson, O., Eastlake, D. and B. Wellington,
|
||||
"Secret Key Transaction Authentication for DNS (TSIG)", RFC
|
||||
2845, May 2000.
|
||||
|
||||
[9] Eastlake, D., "DNS Request and Transaction Signatures (
|
||||
SIG(0)s)", RFC 2931, September 2000.
|
||||
|
||||
[10] Wellington, B., "Secure Domain Name System (DNS) Dynamic
|
||||
Update", RFC 3007, November 2000.
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Jakob Schlyter
|
||||
Carlstedt Research & Technology
|
||||
Stora Badhusgatan 18-20
|
||||
Goteborg SE-411 21
|
||||
Sweden
|
||||
|
||||
EMail: jakob@crt.se
|
||||
URI: http://www.crt.se/~jakob/
|
||||
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 8]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
Wesley Griffin
|
||||
Network Associates Laboratories
|
||||
15204 Omega Drive Suite 300
|
||||
Rockville, MD 20850
|
||||
USA
|
||||
|
||||
EMail: wgriffin@tislabs.com
|
||||
URI: http://www.nailabs.com/
|
||||
|
||||
Appendix A. Acknowledgements
|
||||
|
||||
The authors gratefully acknowledges, in no particular order, the
|
||||
contributions of the following persons:
|
||||
|
||||
Martin Fredriksson
|
||||
|
||||
Olafur Gudmundsson
|
||||
|
||||
Edward Lewis
|
||||
|
||||
Bill Sommerfeld
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 9]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
Intellectual Property Statement
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
intellectual property or other rights that might be claimed to
|
||||
pertain to the implementation or use of the technology described in
|
||||
this document or the extent to which any license under such rights
|
||||
might or might not be available; neither does it represent that it
|
||||
has made any effort to identify any such rights. Information on the
|
||||
IETF's procedures with respect to rights in standards-track and
|
||||
standards-related documentation can be found in BCP-11. Copies of
|
||||
claims of rights made available for publication and any assurances of
|
||||
licenses to be made available, or the result of an attempt made to
|
||||
obtain a general license or permission for the use of such
|
||||
proprietary rights by implementors or users of this specification can
|
||||
be obtained from the IETF Secretariat.
|
||||
|
||||
The IETF invites any interested party to bring to its attention any
|
||||
copyrights, patents or patent applications, or other proprietary
|
||||
rights which may cover technology that may be required to practice
|
||||
this standard. Please address the information to the IETF Executive
|
||||
Director.
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assignees.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 10]
|
||||
|
||||
Internet-Draft DNS and SSH fingerprints April 2003
|
||||
|
||||
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is currently provided by the
|
||||
Internet Society.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Schlyter & Griffin Expires October 1, 2003 [Page 11]
|
||||
|
1626
doc/draft-ietf-secsh-filexfer-02.txt
Обычный файл
1626
doc/draft-ietf-secsh-filexfer-02.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
1962
doc/draft-ietf-secsh-filexfer-03.txt
Обычный файл
1962
doc/draft-ietf-secsh-filexfer-03.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
2130
doc/draft-ietf-secsh-filexfer-04.txt
Обычный файл
2130
doc/draft-ietf-secsh-filexfer-04.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
120
doc/draft-ietf-secsh-fingerprint-01.txt
Обычный файл
120
doc/draft-ietf-secsh-fingerprint-01.txt
Обычный файл
@ -0,0 +1,120 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
INTERNET-DRAFT Markus Friedl
|
||||
draft-ietf-secsh-fingerprint-01.txt The OpenBSD Project
|
||||
Expires in six months September 2003
|
||||
|
||||
|
||||
SSH Fingerprint Format
|
||||
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as Internet-
|
||||
Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other docu- ments at
|
||||
any time. It is inappropriate to use Internet- Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at
|
||||
http://www.ietf.org/ietf/1id-abstracts.txt
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
Distribution of this memo is unlimited.
|
||||
|
||||
Abstract
|
||||
|
||||
This document formally documents the fingerprint format in use for
|
||||
verifying public keys from SSH clients and servers.
|
||||
|
||||
Introduction
|
||||
|
||||
The security of the SSH protocols relies on the verification of
|
||||
public host keys. Since public keys tend to be very large, it is
|
||||
difficult for a human to verify an entire host key. Even with a PKI
|
||||
in place, it is useful to have a standard for exchanging short
|
||||
fingerprints of public keys.
|
||||
|
||||
This document formally describes the simple key fingerprint format.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Friedl [Page 1]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
INTERNET-DRAFT March 2003
|
||||
|
||||
|
||||
Fingerprint Format
|
||||
|
||||
The fingerprint of a public key consists of the output of the MD5
|
||||
message-digest algorithm [RFC-1321]. The input to the algorithm is
|
||||
the public key blob as described in [SSH-TRANS]. The output of the
|
||||
algorithm is presented to the user as a sequence of 16 octets printed
|
||||
as hexadecimal with lowercase letters and separated by colons.
|
||||
|
||||
For example: "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87"
|
||||
|
||||
References
|
||||
|
||||
[SSH-TRANS] Ylonen, T., et al: "SSH Transport Layer Protocol",
|
||||
Internet Draft, draft-secsh-transport-15.txt
|
||||
|
||||
[RFC-1321] R. Rivest: "The MD5 Message-Digest Algorithm", April 1992.
|
||||
|
||||
[RFC-2026] S. Bradner: "The Internet Standards Process -- Revision
|
||||
3", October 1996.
|
||||
|
||||
Author's Address:
|
||||
|
||||
Markus Friedl
|
||||
markus@openbsd.org
|
||||
Munich, Germany
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Friedl [Page 2]
|
||||
|
||||
|
1509
doc/draft-ietf-secsh-gsskeyex-06.txt
Обычный файл
1509
doc/draft-ietf-secsh-gsskeyex-06.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
619
doc/draft-ietf-secsh-newmodes-00.txt
Обычный файл
619
doc/draft-ietf-secsh-newmodes-00.txt
Обычный файл
@ -0,0 +1,619 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group M. Bellare
|
||||
Internet-Draft T. Kohno
|
||||
Expires: September 20, 2003 UC San Diego
|
||||
C. Namprempre
|
||||
Thammasat University
|
||||
March 20, 2003
|
||||
|
||||
|
||||
SSH Transport Layer Encryption Modes
|
||||
|
||||
draft-ietf-secsh-newmodes-00.txt
|
||||
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as Internet-
|
||||
Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at
|
||||
http://www.ietf.org/ietf/1id-abstracts.txt.
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
This Internet-Draft will expire on September 20, 2003.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
Abstract
|
||||
|
||||
Researchers have recently discovered that the authenticated
|
||||
encryption portion of the current SSH Transport Protocol is
|
||||
vulnerable to several attacks.
|
||||
|
||||
This document describes new symmetric encryption methods for the SSH
|
||||
Transport Protocol and gives specific recommendations on how
|
||||
|
||||
|
||||
|
||||
Bellare, Kohno, and Namprempre [Page 1]
|
||||
|
||||
Internet Draft Month, Year
|
||||
|
||||
|
||||
frequently SSH implementations should rekey.
|
||||
|
||||
Bellare, Kohno, and Namprempre [ACM CCS 2002] prove that if an SSH
|
||||
application implements the modifications described in this document,
|
||||
then the symmetric cryptographic portion of that application will
|
||||
provably resist chosen-plaintext, chosen-ciphertext, reaction-based
|
||||
privacy and integrity/authenticity attacks.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
2. Conventions Used in This Document . . . . . . . . . . . . . . 2
|
||||
3. Rekeying . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
3.1 First Rekeying Recommendation . . . . . . . . . . . . . . . . 3
|
||||
3.2 Second Rekeying Recommendation . . . . . . . . . . . . . . . . 3
|
||||
4. Encryption Modes . . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
5. Security Considerations . . . . . . . . . . . . . . . . . . . 6
|
||||
5.1 Rekeying Considerations . . . . . . . . . . . . . . . . . . . 7
|
||||
5.2 Encryption Method Considerations . . . . . . . . . . . . . . . 8
|
||||
References . . . . . . . . . . . . . . . . . . . . . . . . . . 9
|
||||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 10
|
||||
Full Copyright Statement . . . . . . . . . . . . . . . . . . . 10
|
||||
|
||||
1. Introduction
|
||||
|
||||
The symmetric portion of the SSH Transport Protocol was designed to
|
||||
provide both privacy and integrity of encapsulated data. Researchers
|
||||
([DAI,BKN]) have, however, recently identified several security
|
||||
problems with the symmetric portion of the SSH Transport Protocol as
|
||||
described in [SSH-TRANS]. For example, the encryption mode specified
|
||||
in [SSH-TRANS] is vulnerable to a chosen-plaintext privacy attack.
|
||||
Additionally, if not rekeyed frequently enough, the SSH Transport
|
||||
Protocol may leak information about payload data. This latter
|
||||
property is true regardless of what encryption mode is used.
|
||||
|
||||
In [BKN] Bellare, Kohno, and Namprempre show how to modify the
|
||||
symmetric portion of the SSH Transport Protocol so that it provably
|
||||
preserves privacy and integrity against chosen-plaintext, chosen-
|
||||
ciphertext, and reaction attacks. This document instantiates the
|
||||
recommendations described in [BKN].
|
||||
|
||||
2. Conventions Used in This Document
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [RFC2119].
|
||||
|
||||
The used data types and terminology are specified in the architecture
|
||||
|
||||
|
||||
|
||||
Bellare, Kohno, and Namprempre [Page 2]
|
||||
|
||||
Internet Draft Month, Year
|
||||
|
||||
|
||||
document [SSH-ARCH].
|
||||
|
||||
The SSH Transport Protocol is specified in the transport document
|
||||
[SSH-TRANS].
|
||||
|
||||
3. Rekeying
|
||||
|
||||
Section 7 of [SSH-TRANS] suggests that SSH implementations rekey
|
||||
after every gigabyte of transmitted data. [SSH-TRANS] does not,
|
||||
however, discuss all the problems that could arise if an SSH
|
||||
implementation does not rekey frequently enough. This section serves
|
||||
to strengthen the suggestion in [SSH-TRANS] by giving firm upper
|
||||
bounds on the tolerable number of encryptions between rekeying
|
||||
operations. In Section 5 we discuss the motivation for these
|
||||
rekeying recommendations in more detail.
|
||||
|
||||
This section makes two recommendations. Informally, the first
|
||||
recommendation is intended to protects against possible information
|
||||
leakage through the MAC tag and the second recommendation is intended
|
||||
to protect against possible information leakage through the block
|
||||
cipher. Note that, depending on the block length of the underlying
|
||||
block cipher and the length of the encrypted packets, the first
|
||||
recommendation may supersede the second recommendation, or visa-
|
||||
versa.
|
||||
|
||||
3.1 First Rekeying Recommendation
|
||||
|
||||
Because of possible information leakage through the MAC tag, SSH
|
||||
implementations SHOULD rekey at least once every 2**32 outgoing
|
||||
packets. More explicitly, after a key exchange an SSH implementation
|
||||
SHOULD NOT send more than 2**32 packets before rekeying again.
|
||||
|
||||
SSH implementations SHOULD also attempt to rekey before receiving
|
||||
more than 2**32 packets since the last rekey operation. The
|
||||
preferred way to do this is to rekey after receiving more than 2**31
|
||||
packets since the last rekey operation.
|
||||
|
||||
3.2 Second Rekeying Recommendation
|
||||
|
||||
Because of a birthday property of block ciphers and some modes of
|
||||
operation, implementations must be careful not to encrypt too many
|
||||
blocks with the same encryption key.
|
||||
|
||||
Let L be the block length (in bits) of an SSH encryption method's
|
||||
block cipher (eg, 128 for AES). If L is at least 128 then, after
|
||||
rekeying, an SSH implementation SHOULD NOT encrypt more than 2**(L/4)
|
||||
blocks before rekeying again. If L is at least 128, then SSH
|
||||
implementations should also attempt to force a rekey before receiving
|
||||
|
||||
|
||||
|
||||
Bellare, Kohno, and Namprempre [Page 3]
|
||||
|
||||
Internet Draft Month, Year
|
||||
|
||||
|
||||
more than 2**(L/4) blocks. If L is less than 128 (which is the case
|
||||
for older ciphers such as 3DES, Blowfish, CAST-128, and IDEA), then,
|
||||
although it may be too expensive to rekey every 2**(L/4) blocks, it
|
||||
is still advisable for SSH implementations to follow the original
|
||||
recommendation in [SSH-TRANS]: rekey at least once every gigabyte of
|
||||
transmitted data.
|
||||
|
||||
Note that if L is less than or equal to 128, then the recommendation
|
||||
in this subsection supersedes the recommendation in Section 3.1. If
|
||||
an SSH implementation uses a block cipher with a larger block size
|
||||
(eg, Rijndael with 256-bit blocks), then the recommendations in the
|
||||
above paragraph may supersede the recommendations in this paragraph
|
||||
(depending on the lengths of the packets).
|
||||
|
||||
4. Encryption Modes
|
||||
|
||||
This document describes new encryption methods for use with the SSH
|
||||
Transport Protocol. These encryption methods are in addition to the
|
||||
encryption methods described in Section 4.3 of [SSH-TRANS].
|
||||
|
||||
Recall from [SSH-TRANS] that the encryption methods in each direction
|
||||
of an SSH connection MUST run independently of each other and that,
|
||||
when encryption is in effect, the packet length, padding length,
|
||||
payload, and padding fields of each packet MUST be encrypted with the
|
||||
chosen method. Further recall that the total length of the
|
||||
concatenation of the packet length, padding length, payload, and
|
||||
padding MUST be a multiple of the cipher's block size when the
|
||||
cipher's block size is greater than or equal to 8 bytes (which is the
|
||||
case for all of the following methods).
|
||||
|
||||
This document describes the following new methods:
|
||||
|
||||
aes128-ctr RECOMMENDED AES (Rijndael) in SDCTR mode,
|
||||
with 128-bit key
|
||||
aes192-ctr RECOMMENDED AES with 192-bit key
|
||||
aes256-ctr RECOMMENDED AES with 256-bit key
|
||||
3des-ctr RECOMMENDED Three-key 3DES in SDCTR mode
|
||||
blowfish-ctr RECOMMENDED Blowfish in SDCTR mode
|
||||
twofish128-ctr RECOMMENDED Twofish in SDCTR mode,
|
||||
with 128-bit key
|
||||
twofish192-ctr OPTIONAL Twofish with 192-bit key
|
||||
twofish256-ctr OPTIONAL Twofish with 256-bit key
|
||||
serpent128-ctr RECOMMENDED Serpent in SDCTR mode, with
|
||||
with 128-bit key
|
||||
serpent192-ctr OPTIONAL Serpent with 192-bit key
|
||||
serpent256-ctr OPTIONAL Serpent with 256-bit key
|
||||
idea-ctr OPTIONAL IDEA in SDCTR mode
|
||||
cast128-ctr OPTIONAL CAST-128 in SDCTR mode
|
||||
|
||||
|
||||
|
||||
Bellare, Kohno, and Namprempre [Page 4]
|
||||
|
||||
Internet Draft Month, Year
|
||||
|
||||
|
||||
The label <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
Обычный файл
506
doc/draft-ietf-secsh-publickeyfile-03.txt
Обычный файл
@ -0,0 +1,506 @@
|
||||
|
||||
|
||||
|
||||
Secure Shell Working Group J. Galbraith
|
||||
Internet-Draft VanDyke Software
|
||||
Expires: April 16, 2003 R. Thayer
|
||||
The Tillerman Group
|
||||
October 16, 2002
|
||||
|
||||
|
||||
SSH Public Key File Format
|
||||
draft-ietf-secsh-publickeyfile-03.txt
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as Internet-
|
||||
Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at http://
|
||||
www.ietf.org/ietf/1id-abstracts.txt.
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
This Internet-Draft will expire on April 16, 2003.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2002). All Rights Reserved.
|
||||
|
||||
Abstract
|
||||
|
||||
This document formally documents the existing public key file format
|
||||
in use for exchanging public keys between different SSH
|
||||
implementations.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Thayer Expires April 16, 2003 [Page 1]
|
||||
|
||||
Internet-Draft SSH Public Key File Format October 2002
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Conventions used in this document . . . . . . . . . . . . . 3
|
||||
2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
3. Key File Format . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
3.1 Line termination Characters . . . . . . . . . . . . . . . . 5
|
||||
3.2 Begin and end markers . . . . . . . . . . . . . . . . . . . 5
|
||||
3.3 Key File Header . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
3.3.1 Subject Header . . . . . . . . . . . . . . . . . . . . . . . 6
|
||||
3.3.2 Comment Header . . . . . . . . . . . . . . . . . . . . . . . 6
|
||||
3.4 Public Key File Body . . . . . . . . . . . . . . . . . . . . 6
|
||||
3.5 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 7
|
||||
References . . . . . . . . . . . . . . . . . . . . . . . . . 8
|
||||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 8
|
||||
Full Copyright Statement . . . . . . . . . . . . . . . . . . 9
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Thayer Expires April 16, 2003 [Page 2]
|
||||
|
||||
Internet-Draft SSH Public Key File Format October 2002
|
||||
|
||||
|
||||
1. Conventions used in this document
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [4].
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Thayer Expires April 16, 2003 [Page 3]
|
||||
|
||||
Internet-Draft SSH Public Key File Format October 2002
|
||||
|
||||
|
||||
2. Introduction
|
||||
|
||||
In order to use public key authentication, public keys must be
|
||||
exchanged between client and server. This document formally
|
||||
describes the existing public key file format, with few exceptions.
|
||||
|
||||
Where this document departs from current practice, it also suggests a
|
||||
mechanism for backwards compatibility.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Galbraith & Thayer Expires April 16, 2003 [Page 4]
|
||||
|
||||
Internet-Draft SSH Public Key File Format October 2002
|
||||
|
||||
|
||||
3. Key File Format
|
||||
|
||||
SSH implementations must share public key files between the client
|
||||
and the server in order interoperate.
|
||||
|
||||
A key file is a text file, containing a sequence of lines. Each line
|
||||
in the file MUST NOT be longer than 72 bytes.
|
||||
|
||||
3.1 Line termination Characters
|
||||
|
||||
In order to achieve the goal of being able to exchange public key
|
||||
files between servers, implementations are REQUIRED to read files
|
||||
using any of the common line termination sequence, <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
Обычный файл
426
doc/draft-ietf-secsh-scp-sftp-ssh-uri-00.txt
Обычный файл
@ -0,0 +1,426 @@
|
||||
Network Working Group S. Suehring
|
||||
Internet-Draft Sentry Insurance
|
||||
Expires February 8, 2004 J. Salowey
|
||||
Cisco Systems
|
||||
August 8, 2003
|
||||
|
||||
|
||||
SCP/SFTP/SSH URI Format
|
||||
draft-ietf-secsh-scp-sftp-ssh-uri-00.txt
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is subject to all provisions
|
||||
of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as
|
||||
Internet-Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six
|
||||
months and may be updated, replaced, or obsoleted by other
|
||||
documents at any time. It is inappropriate to use Internet-Drafts
|
||||
as reference material or to cite them other than as "work in
|
||||
progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at
|
||||
http://www.ietf.org/1id-abstracts.html
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html
|
||||
|
||||
This Internet Draft will expire on February 8, 2004.
|
||||
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes the Uniform Resource Identifiers used to
|
||||
locate resources for the SCP, SFTP, and SSH protocols. The document
|
||||
describes the generic syntax involved in URI definitions as well as
|
||||
specific definitions for each protocol. These specific definitions
|
||||
may include user credentials such as username and password and also
|
||||
may include other parameters such as fingerprint. In addition,
|
||||
security considerations and examples are also provided within this
|
||||
document.
|
||||
|
||||
|
||||
General Syntax
|
||||
|
||||
The URI for each protocol shall consist of the scheme and the scheme
|
||||
specific portion separated by a colon ":", as discussed in RFC 2396
|
||||
[1]. This specification shall adopt the definitions "port", "host",
|
||||
"scheme", "userinfo", and "authority" from RFC 2396.
|
||||
|
||||
|
||||
Suehring & Salowey Expires February 8, 2004 [Page 1]
|
||||
|
||||
Internet Draft SCP/SFTP/SSH URI Format August 8, 2003
|
||||
|
||||
SSH URI
|
||||
|
||||
The SSH scheme shall consist of the protocol acronym followed by a
|
||||
colon ":" and a double slash "//" in accordance with RFC 2718 [2].
|
||||
|
||||
The first component of the scheme specific portion MAY include
|
||||
credentials (userinfo) consisting of a username and optionally also
|
||||
including a password. Including the password in the URL is NOT
|
||||
RECOMMENDED. The username and password components are separated by
|
||||
a single colon ":".
|
||||
|
||||
Following the userinfo, if present, the at-sign "@" shall
|
||||
precede the authority section of the URI. Optionally, the
|
||||
authority section MAY also include the port preceded by a colon ":".
|
||||
If the port is not included, port 22 is assumed. Following the port
|
||||
additional parameters may be specified. These parameters are
|
||||
defined in the connection parameters section.
|
||||
|
||||
ssh_URI = "ssh://" [ userinfo "@" ] host [ ":" port ]
|
||||
[;conn-parameter=value]
|
||||
|
||||
SCP and SFTP URI
|
||||
|
||||
For SCP and SFTP, the scheme portion (scp: or sftp:) is followed by
|
||||
a double slash "//".
|
||||
|
||||
Both SCP and SFTP URLs are terminated by a single slash "/" followed
|
||||
by the path information to the requested resource.
|
||||
|
||||
The first component of the scheme specific portion MAY include
|
||||
credentials (userinfo) consisting of a username and optionally also
|
||||
including a password. Including the password in the URL is NOT
|
||||
RECOMMENDED. The username and password components are separated by
|
||||
a single colon ":".
|
||||
|
||||
Following the userinfo, if present, the at-sign "@" shall precede
|
||||
the authority section of the URL. Optionally, the authority section
|
||||
MAY also include the port preceded by a colon ":". If the port is
|
||||
not included, port 22 is assumed. Following the port additional
|
||||
parameters may be specified. These parameters are defined in the
|
||||
connection parameters section.
|
||||
|
||||
scp_URI = "scp://" [ userinfo "@" ] host [ ":" port ]
|
||||
[ ; parameter = value ] [ abs_path ]
|
||||
|
||||
Following the port additional parameters may be specified. These
|
||||
parameters are defined in the connection parameters section.
|
||||
Following the path additional sftp specific parameters may be
|
||||
specified.
|
||||
|
||||
sftp_URI = "sftp://" [ userinfo "@" ] host [ ":" port ]
|
||||
[;conn-parameter=value] [ abs_path ] [;sftp-parameter=value]
|
||||
|
||||
|
||||
|
||||
Suehring & Salowey Expires February 8, 2004 [Page 2]
|
||||
|
||||
Internet Draft SCP/SFTP/SSH URI Format August 8, 2003
|
||||
|
||||
|
||||
Parameters
|
||||
|
||||
SSH connection parameters
|
||||
|
||||
The following parameters are associated with an SSH connection and
|
||||
are applicable to SSH, SFTP and SCP. All parameters are optional
|
||||
and MUST NOT overwrite configured defaults. Individual parameters
|
||||
are separated by a comma (",").
|
||||
|
||||
fingerprint
|
||||
|
||||
The fingerprint parameter contains the fingerprint of the host key
|
||||
for the host specified in the URL. The fingerprint is encoded as
|
||||
in [3]. This parameter MUST NOT overwrite a key that is already
|
||||
configured for the host. They fingerprint MAY be used to validate
|
||||
the authenticity of the host key if the URL was obtained from an
|
||||
authenticated source with its integrity protected. If this
|
||||
parameter is not included then the validity of the host key is
|
||||
validated using another method. See Security Considerations section
|
||||
for additional considerations. There MUST be only one fingerprint
|
||||
parameter for a given URL.
|
||||
|
||||
cipher
|
||||
|
||||
The cipher parameter indicates an acceptable encryption mechanism to
|
||||
use in making the connection. The value is the string specifying the
|
||||
SSH cipher type. This parameter MUST NOT add a mechanism to a
|
||||
configured list of default configured acceptable encryption types.
|
||||
If this parameter is not specified then the default configured cipher
|
||||
list is used. There may be more than one cipher parameter.
|
||||
|
||||
integrity
|
||||
|
||||
The integrity parameter indicates an acceptable data integrity
|
||||
mechanism to use in making the connection. The value is the string
|
||||
specifying the SSH data integrity type. This parameter MUST NOT add
|
||||
a mechanism to a configured list of default configured acceptable
|
||||
data integrity types. If this parameter is not specified then the
|
||||
default configured data integrity list is used. There may be more
|
||||
than one integrity parameter.
|
||||
|
||||
key-xchg
|
||||
|
||||
The key-xchg parameter indicates an acceptable key exchange mechanism
|
||||
to use when making the connection. The value is the string
|
||||
specifying the SSH key exchange type. This parameter MUST NOT add a
|
||||
mechanism to a configured list of default configured acceptable key
|
||||
exchange types. If this parameter is not specified then the default
|
||||
configured key exchange list is used. There may be more than one
|
||||
key-xchg parameter.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Suehring & Salowey Expires February 8, 2004 [Page 3]
|
||||
|
||||
Internet Draft SCP/SFTP/SSH URI Format August 8, 2003
|
||||
|
||||
host-key-alg
|
||||
|
||||
The host-key-alg parameter indicates an host key to use when making
|
||||
the connection. The value is the string specifying the SSH host key
|
||||
type. This parameter MUST NOT add a mechanism to a configured list
|
||||
of default configured acceptable host key types. If this parameter
|
||||
is not specified then the default configured host key type list is
|
||||
used. There may be more than one host-key-alg parameter.
|
||||
|
||||
user-auth
|
||||
|
||||
The user-auth parameter indicates a user authentication mechanism to
|
||||
use when making the connection. The value is the string specifying
|
||||
the SSH user authentication mechanism type. This parameter MUST NOT
|
||||
add a mechanism to a configured list of default configured
|
||||
acceptable user authentication mechanism types. If this parameter
|
||||
is not specified then the default configured user authentication
|
||||
mechanism type list is used. There may be more than one user-auth
|
||||
parameter.
|
||||
|
||||
SFTP Parameters
|
||||
|
||||
The SFTP parameters determine how to handle the file transfer
|
||||
character translation.
|
||||
|
||||
newline
|
||||
|
||||
The newline parameter determines how the server translates new line
|
||||
indicators. The possible choices are usually "\r" or "\n" or "\r\n".
|
||||
The default is "\r\n".
|
||||
|
||||
typecode
|
||||
|
||||
The typecode identifies the type of file which determines how it
|
||||
will be treated. Possible values are "i" for binary files, "a" for
|
||||
text files, and "d" for directory listings.
|
||||
|
||||
|
||||
Examples
|
||||
|
||||
The following section shows basic examples of URLs for each
|
||||
protocol. This section should not be considered to include all
|
||||
possible combinations of URLs for each protocol.
|
||||
|
||||
ssh://user@host
|
||||
|
||||
ssh://user@host:2222
|
||||
|
||||
ssh://joeuser@example.com;fingerprint=c1:b1:30:29:d7:b8:de:6c
|
||||
:97:77:10:d7:46:41:63:87,cipher=aes-cbc
|
||||
|
||||
scp://user:password@host/file.txt
|
||||
|
||||
sftp://user@host/dir/path/file.txt
|
||||
|
||||
|
||||
Suehring & Salowey Expires February 8, 2004 [Page 4]
|
||||
|
||||
Internet Draft SCP/SFTP/SSH URI Format August 8, 2003
|
||||
|
||||
sftp://joeuser@example.com:2222;fingerprint=c1:b1:30:29:d7:b8
|
||||
:de:6c:97:77:10:d7:46:41:63:87,cipher=
|
||||
aes-cbc/pub/docs/test.txt;typecode=a
|
||||
|
||||
|
||||
Security Considerations
|
||||
|
||||
In general, URIs themselves have no security considerations.
|
||||
However, since the password for each scheme can optionally be
|
||||
included within the URL it should be noted that doing so poses a
|
||||
security risk. Since URLs are usually sent in the clear with no
|
||||
encryption or other security, any password or other credentials
|
||||
(userinfo) included could be seen by a potential attacker.
|
||||
|
||||
The fingerprint should only be used to validate the host key only if
|
||||
the URL can be determined to be authentic from a trusted entity.
|
||||
For example, the URL may be received through secure email or HTTPS
|
||||
from a trusted and verifiable source. It is possible that the SSH
|
||||
implementation may not be able to determine if the URL is authentic
|
||||
in which case it SHOULD prompt the user to either allow or disallow
|
||||
the connection based on the information provided. The SSH
|
||||
implementation MUST NOT overwrite a currently configured public key
|
||||
based on the URL alone.
|
||||
|
||||
The other connection parameters MUST NOT add any mechanism to the
|
||||
list of configured acceptable mechanisms defined in the SSH client.
|
||||
|
||||
Normative References
|
||||
|
||||
[1] Berners-Lee, T., Fielding, R., Masinter, L., "Uniform Resource
|
||||
Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
|
||||
|
||||
[2] Masinter, L., et. al., "Guidelines for new URL Schemes", RFC
|
||||
2718, November 1999.
|
||||
|
||||
[3] Markus Friedl, "SSH Fingerprint Format",
|
||||
http://www.ietf.org/internet-drafts/
|
||||
draft-ietf-secsh-fingerprint-01.txt,
|
||||
work in progress
|
||||
|
||||
Non-Normative References
|
||||
|
||||
Mealling, M., Denenberg, R., "Report from the Joint W3C/IETF URI
|
||||
Planning Interest Group: Uniform Resource Identifiers (URIs), URLs,
|
||||
and Uniform Resource Names (URNs): Clarifications and
|
||||
Recommendations", RFC 3305, August 2002.
|
||||
|
||||
|
||||
Author Information
|
||||
|
||||
Steve Suehring
|
||||
Sentry Insurance
|
||||
1800 North Point Dr, G2/61-17
|
||||
Stevens Point, WI 54481
|
||||
suehring@braingia.com
|
||||
|
||||
Joseph Salowey
|
||||
Cisco Systems
|
||||
2901 Third Avenue
|
||||
Seattle, WA 98121
|
||||
E-mail: jsalowey@cisco.com
|
||||
|
||||
|
||||
Suehring & Salowey Expires February 8, 2004 [Page 5]
|
||||
|
||||
Internet Draft SCP/SFTP/SSH URI Format August 8, 2003
|
||||
|
||||
Intellectual Property Statement
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
intellectual property or other rights that might be claimed to
|
||||
pertain to the implementation or use of the technology described in
|
||||
this document or the extent to which any license under such rights
|
||||
might or might not be available; neither does it represent that it
|
||||
has made any effort to identify any such rights. Information on the
|
||||
IETF's procedures with respect to rights in standards-track and
|
||||
standards-related documentation can be found in BCP-11. Copies of
|
||||
claims of rights made available for publication and any assurances of
|
||||
licenses to be made available, or the result of an attempt made to
|
||||
obtain a general license or permission for the use of such
|
||||
proprietary rights by implementors or users of this specification can
|
||||
be obtained from the IETF Secretariat.
|
||||
|
||||
The IETF invites any interested party to bring to its attention any
|
||||
copyrights, patents or patent applications, or other proprietary
|
||||
rights which may cover technology that may be required to practice
|
||||
this standard. Please address the information to the IETF Executive
|
||||
Director.
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2003). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assignees.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Suehring & Salowey Expires February 8, 2004 [Page 6]
|
||||
|
||||
Internet Draft SCP/SFTP/SSH URI Format August 8, 2003
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is currently provided by the
|
||||
Internet Society.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Suehring & Salowey Expires February 8, 2004 [Page 7]
|
1624
doc/draft-ietf-secsh-transport-16.txt
Обычный файл
1624
doc/draft-ietf-secsh-transport-16.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
840
doc/draft-ietf-secsh-userauth-17.txt
Обычный файл
840
doc/draft-ietf-secsh-userauth-17.txt
Обычный файл
@ -0,0 +1,840 @@
|
||||
|
||||
|
||||
Network Working Group T. Ylonen
|
||||
Internet-Draft T. Kivinen
|
||||
Expires: March 2, 2003 SSH Communications Security Corp
|
||||
M. Saarinen
|
||||
University of Jyvaskyla
|
||||
T. Rinne
|
||||
S. Lehtinen
|
||||
SSH Communications Security Corp
|
||||
September 2002
|
||||
|
||||
|
||||
SSH Authentication Protocol
|
||||
draft-ietf-secsh-userauth-17.txt
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document is an Internet-Draft and is in full conformance with
|
||||
all provisions of Section 10 of RFC2026.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF), its areas, and its working groups. Note that
|
||||
other groups may also distribute working documents as Internet-
|
||||
Drafts.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six
|
||||
months and may be updated, replaced, or obsoleted by other
|
||||
documents at any time. It is inappropriate to use Internet-Drafts
|
||||
as reference material or to cite them other than as "work in
|
||||
progress."
|
||||
|
||||
The list of current Internet-Drafts can be accessed at
|
||||
http://www.ietf.org/ietf/1id-abstracts.txt.
|
||||
|
||||
The list of Internet-Draft Shadow Directories can be accessed at
|
||||
http://www.ietf.org/shadow.html.
|
||||
|
||||
This Internet-Draft will expire on March 2, 2003.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2002). All Rights Reserved.
|
||||
|
||||
Abstract
|
||||
|
||||
SSH is a protocol for secure remote login and other secure network
|
||||
services over an insecure network. This document describes the
|
||||
SSH authentication protocol framework and public key, password,
|
||||
and host-based client authentication methods. Additional
|
||||
authentication methods are described in separate documents. The
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 1]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
SSH authentication protocol runs on top of the SSH transport layer
|
||||
protocol and provides a single authenticated tunnel for the SSH
|
||||
connection protocol.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
2. The Authentication Protocol Framework . . . . . . . . . . . . 3
|
||||
2.1 Authentication Requests . . . . . . . . . . . . . . . . . . . 4
|
||||
2.2 Responses to Authentication Requests . . . . . . . . . . . . . 5
|
||||
2.3 The "none" Authentication Request . . . . . . . . . . . . . . 6
|
||||
2.4 Completion of User Authentication . . . . . . . . . . . . . . 6
|
||||
2.5 Banner Message . . . . . . . . . . . . . . . . . . . . . . . . 6
|
||||
3. Authentication Protocol Message Numbers . . . . . . . . . . . 7
|
||||
4. Public Key Authentication Method: publickey . . . . . . . . . 7
|
||||
5. Password Authentication Method: password . . . . . . . . . . . 9
|
||||
6. Host-Based Authentication: hostbased . . . . . . . . . . . . . 11
|
||||
7. Security Considerations . . . . . . . . . . . . . . . . . . . 12
|
||||
8. Intellectual Property . . . . . . . . . . . . . . . . . . . . 12
|
||||
9. Additional Information . . . . . . . . . . . . . . . . . . . . 13
|
||||
References . . . . . . . . . . . . . . . . . . . . . . . . . . 13
|
||||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 14
|
||||
Full Copyright Statement . . . . . . . . . . . . . . . . . . . 15
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 2]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
The SSH authentication protocol is a general-purpose user
|
||||
authentication protocol. It is intended to be run over the SSH
|
||||
transport layer protocol [SSH-TRANS]. This protocol assumes that
|
||||
the underlying protocols provide integrity and confidentiality
|
||||
protection.
|
||||
|
||||
This document should be read only after reading the SSH
|
||||
architecture document [SSH-ARCH]. This document freely uses
|
||||
terminology and notation from the architecture document without
|
||||
reference or further explanation.
|
||||
|
||||
The service name for this protocol is "ssh-userauth".
|
||||
|
||||
When this protocol starts, it receives the session identifier from
|
||||
the lower-level protocol (this is the exchange hash H from the
|
||||
first key exchange). The session identifier uniquely identifies
|
||||
this session and is suitable for signing in order to prove
|
||||
ownership of a private key. This protocol also needs to know
|
||||
whether the lower-level protocol provides confidentiality
|
||||
protection.
|
||||
|
||||
2. The Authentication Protocol Framework
|
||||
|
||||
The server drives the authentication by telling the client which
|
||||
authentication methods can be used to continue the exchange at any
|
||||
given time. The client has the freedom to try the methods listed
|
||||
by the server in any order. This gives the server complete
|
||||
control over the authentication process if desired, but also gives
|
||||
enough flexibility for the client to use the methods it supports
|
||||
or that are most convenient for the user, when multiple methods
|
||||
are offered by the server.
|
||||
|
||||
Authentication methods are identified by their name, as defined in
|
||||
[SSH-ARCH]. The "none" method is reserved, and MUST NOT be listed
|
||||
as supported. However, it MAY be sent by the client. The server
|
||||
MUST always reject this request, unless the client is to be
|
||||
allowed in without any authentication, in which case the server
|
||||
MUST accept this request. The main purpose of sending this
|
||||
request is to get the list of supported methods from the server.
|
||||
|
||||
The server SHOULD have a timeout for authentication, and
|
||||
disconnect if the authentication has not been accepted within the
|
||||
timeout period. The RECOMMENDED timeout period is 10 minutes.
|
||||
Additionally, the implementation SHOULD limit the number of failed
|
||||
authentication attempts a client may perform in a single session
|
||||
(the RECOMMENDED limit is 20 attempts). If the threshold is
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 3]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
exceeded, the server SHOULD disconnect.
|
||||
|
||||
2.1 Authentication Requests
|
||||
|
||||
All authentication requests MUST use the following message format.
|
||||
Only the first few fields are defined; the remaining fields depend
|
||||
on the authentication method.
|
||||
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name (in ISO-10646 UTF-8 encoding [RFC2279])
|
||||
string service name (in US-ASCII)
|
||||
string method name (US-ASCII)
|
||||
The rest of the packet is method-specific.
|
||||
|
||||
The user name and service are repeated in every new authentication
|
||||
attempt, and MAY change. The server implementation MUST carefully
|
||||
check them in every message, and MUST flush any accumulated
|
||||
authentication states if they change. If it is unable to flush
|
||||
some authentication state, it MUST disconnect if the user or
|
||||
service name changes.
|
||||
|
||||
The service name specifies the service to start after
|
||||
authentication. There may be several different authenticated
|
||||
services provided. If the requested service is not available, the
|
||||
server MAY disconnect immediately or at any later time. Sending a
|
||||
proper disconnect message is RECOMMENDED. In any case, if the
|
||||
service does not exist, authentication MUST NOT be accepted.
|
||||
|
||||
If the requested user does not exist, the server MAY disconnect,
|
||||
or MAY send a bogus list of acceptable authentication methods, but
|
||||
never accept any. This makes it possible for the server to avoid
|
||||
disclosing information on which accounts exist. In any case, if
|
||||
the user does not exist, the authentication request MUST NOT be
|
||||
accepted.
|
||||
|
||||
While there is usually little point for clients to send requests
|
||||
that the server does not list as acceptable, sending such requests
|
||||
is not an error, and the server SHOULD simply reject requests that
|
||||
it does not recognize.
|
||||
|
||||
An authentication request MAY result in a further exchange of
|
||||
messages. All such messages depend on the authentication method
|
||||
used, and the client MAY at any time continue with a new
|
||||
SSH_MSG_USERAUTH_REQUEST message, in which case the server MUST
|
||||
abandon the previous authentication attempt and continue with the
|
||||
new one.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 4]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
2.2 Responses to Authentication Requests
|
||||
|
||||
If the server rejects the authentication request, it MUST respond
|
||||
with the following:
|
||||
|
||||
byte SSH_MSG_USERAUTH_FAILURE
|
||||
string authentications that can continue
|
||||
boolean partial success
|
||||
|
||||
"Authentications that can continue" is a comma-separated list of
|
||||
authentication method names that may productively continue the
|
||||
authentication dialog.
|
||||
|
||||
It is RECOMMENDED that servers only include those methods in the
|
||||
list that are actually useful. However, it is not illegal to
|
||||
include methods that cannot be used to authenticate the user.
|
||||
|
||||
Already successfully completed authentications SHOULD NOT be
|
||||
included in the list, unless they really should be performed again
|
||||
for some reason.
|
||||
|
||||
"Partial success" MUST be TRUE if the authentication request to
|
||||
which this is a response was successful. It MUST be FALSE if the
|
||||
request was not successfully processed.
|
||||
|
||||
When the server accepts authentication, it MUST respond with the
|
||||
following:
|
||||
|
||||
byte SSH_MSG_USERAUTH_SUCCESS
|
||||
|
||||
Note that this is not sent after each step in a multi-method
|
||||
authentication sequence, but only when the authentication is
|
||||
complete.
|
||||
|
||||
The client MAY send several authentication requests without
|
||||
waiting for responses from previous requests. The server MUST
|
||||
process each request completely and acknowledge any failed
|
||||
requests with a SSH_MSG_USERAUTH_FAILURE message before processing
|
||||
the next request.
|
||||
|
||||
A request that results in further exchange of messages will be
|
||||
aborted by a second request. It is not possible to send a second
|
||||
request without waiting for a response from the server, if the
|
||||
first request will result in further exchange of messages. No
|
||||
SSH_MSG_USERAUTH_FAILURE message will be sent for the aborted
|
||||
method.
|
||||
|
||||
SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. When
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 5]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication
|
||||
requests received after that SHOULD be silently ignored.
|
||||
|
||||
Any non-authentication messages sent by the client after the
|
||||
request that resulted in SSH_MSG_USERAUTH_SUCCESS being sent MUST
|
||||
be passed to the service being run on top of this protocol. Such
|
||||
messages can be identified by their message numbers (see Section
|
||||
Message Numbers (Section 3)).
|
||||
|
||||
2.3 The "none" Authentication Request
|
||||
|
||||
A client may request a list of authentication methods that may
|
||||
continue by using the "none" authentication method.
|
||||
|
||||
If no authentication at all is needed for the user, the server
|
||||
MUST return SSH_MSG_USERAUTH_SUCCESS. Otherwise, the server MUST
|
||||
return SSH_MSG_USERAUTH_FAILURE and MAY return with it a list of
|
||||
authentication methods that can continue.
|
||||
|
||||
This method MUST NOT be listed as supported by the server.
|
||||
|
||||
2.4 Completion of User Authentication
|
||||
|
||||
Authentication is complete when the server has responded with
|
||||
SSH_MSG_USERAUTH_SUCCESS; all authentication related messages
|
||||
received after sending this message SHOULD be silently ignored.
|
||||
|
||||
After sending SSH_MSG_USERAUTH_SUCCESS, the server starts the
|
||||
requested service.
|
||||
|
||||
2.5 Banner Message
|
||||
|
||||
In some jurisdictions, sending a warning message before
|
||||
authentication may be relevant for getting legal protection. Many
|
||||
UNIX machines, for example, normally display text from
|
||||
`/etc/issue', or use "tcp wrappers" or similar software to display
|
||||
a banner before issuing a login prompt.
|
||||
|
||||
The SSH server may send a SSH_MSG_USERAUTH_BANNER message at any
|
||||
time before authentication is successful. This message contains
|
||||
text to be displayed to the client user before authentication is
|
||||
attempted. The format is as follows:
|
||||
|
||||
byte SSH_MSG_USERAUTH_BANNER
|
||||
string message (ISO-10646 UTF-8)
|
||||
string language tag (as defined in [RFC1766])
|
||||
|
||||
The client SHOULD by default display the message on the screen.
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 6]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
However, since the message is likely to be sent for every login
|
||||
attempt, and since some client software will need to open a
|
||||
separate window for this warning, the client software may allow
|
||||
the user to explicitly disable the display of banners from the
|
||||
server. The message may consist of multiple lines.
|
||||
|
||||
If the message string is displayed, control character filtering
|
||||
discussed in [SSH-ARCH] SHOULD be used to avoid attacks by sending
|
||||
terminal control characters.
|
||||
|
||||
3. Authentication Protocol Message Numbers
|
||||
|
||||
All message numbers used by this authentication protocol are in
|
||||
the range from 50 to 79, which is part of the range reserved for
|
||||
protocols running on top of the SSH transport layer protocol.
|
||||
|
||||
Message numbers of 80 and higher are reserved for protocols
|
||||
running after this authentication protocol, so receiving one of
|
||||
them before authentication is complete is an error, to which the
|
||||
server MUST respond by disconnecting (preferably with a proper
|
||||
disconnect message sent first to ease troubleshooting).
|
||||
|
||||
After successful authentication, such messages are passed to the
|
||||
higher-level service.
|
||||
|
||||
These are the general authentication message codes:
|
||||
|
||||
#define SSH_MSG_USERAUTH_REQUEST 50
|
||||
#define SSH_MSG_USERAUTH_FAILURE 51
|
||||
#define SSH_MSG_USERAUTH_SUCCESS 52
|
||||
#define SSH_MSG_USERAUTH_BANNER 53
|
||||
|
||||
In addition to the above, there is a range of message numbers
|
||||
(60..79) reserved for method-specific messages. These messages
|
||||
are only sent by the server (client sends only
|
||||
SSH_MSG_USERAUTH_REQUEST messages). Different authentication
|
||||
methods reuse the same message numbers.
|
||||
|
||||
4. Public Key Authentication Method: publickey
|
||||
|
||||
The only REQUIRED authentication method is public key
|
||||
authentication. All implementations MUST support this method;
|
||||
however, not all users need to have public keys, and most local
|
||||
policies are not likely to require public key authentication for
|
||||
all users in the near future.
|
||||
|
||||
With this method, the possession of a private key serves as
|
||||
authentication. This method works by sending a signature created
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 7]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
with a private key of the user. The server MUST check that the
|
||||
key is a valid authenticator for the user, and MUST check that the
|
||||
signature is valid. If both hold, the authentication request MUST
|
||||
be accepted; otherwise it MUST be rejected. (Note that the server
|
||||
MAY require additional authentications after successful
|
||||
authentication.)
|
||||
|
||||
Private keys are often stored in an encrypted form at the client
|
||||
host, and the user must supply a passphrase before the signature
|
||||
can be generated. Even if they are not, the signing operation
|
||||
involves some expensive computation. To avoid unnecessary
|
||||
processing and user interaction, the following message is provided
|
||||
for querying whether authentication using the key would be
|
||||
acceptable.
|
||||
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service
|
||||
string "publickey"
|
||||
boolean FALSE
|
||||
string public key algorithm name
|
||||
string public key blob
|
||||
|
||||
Public key algorithms are defined in the transport layer
|
||||
specification [SSH-TRANS]. The public key blob may contain
|
||||
certificates.
|
||||
|
||||
Any public key algorithm may be offered for use in authentication.
|
||||
In particular, the list is not constrained by what was negotiated
|
||||
during key exchange. If the server does not support some
|
||||
algorithm, it MUST simply reject the request.
|
||||
|
||||
The server MUST respond to this message with either
|
||||
SSH_MSG_USERAUTH_FAILURE or with the following:
|
||||
|
||||
byte SSH_MSG_USERAUTH_PK_OK
|
||||
string public key algorithm name from the request
|
||||
string public key blob from the request
|
||||
|
||||
To perform actual authentication, the client MAY then send a
|
||||
signature generated using the private key. The client MAY send
|
||||
the signature directly without first verifying whether the key is
|
||||
acceptable. The signature is sent using the following packet:
|
||||
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service
|
||||
string "publickey"
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 8]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
boolean TRUE
|
||||
string public key algorithm name
|
||||
string public key to be used for authentication
|
||||
string signature
|
||||
|
||||
Signature is a signature by the corresponding private key over the
|
||||
following data, in the following order:
|
||||
|
||||
string session identifier
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service
|
||||
string "publickey"
|
||||
boolean TRUE
|
||||
string public key algorithm name
|
||||
string public key to be used for authentication
|
||||
|
||||
When the server receives this message, it MUST check whether the
|
||||
supplied key is acceptable for authentication, and if so, it MUST
|
||||
check whether the signature is correct.
|
||||
|
||||
If both checks succeed, this method is successful. Note that the
|
||||
server may require additional authentications. The server MUST
|
||||
respond with SSH_MSG_USERAUTH_SUCCESS (if no more authentications
|
||||
are needed), or SSH_MSG_USERAUTH_FAILURE (if the request failed,
|
||||
or more authentications are needed).
|
||||
|
||||
The following method-specific message numbers are used by the
|
||||
publickey authentication method.
|
||||
|
||||
/* Key-based */
|
||||
#define SSH_MSG_USERAUTH_PK_OK 60
|
||||
|
||||
|
||||
5. Password Authentication Method: password
|
||||
|
||||
Password authentication uses the following packets. Note that a
|
||||
server MAY request the user to change the password. All
|
||||
implementations SHOULD support password authentication.
|
||||
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service
|
||||
string "password"
|
||||
boolean FALSE
|
||||
string plaintext password (ISO-10646 UTF-8)
|
||||
|
||||
Note that the password is encoded in ISO-10646 UTF-8. It is up to
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 9]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
the server how it interprets the password and validates it against
|
||||
the password database. However, if the client reads the password
|
||||
in some other encoding (e.g., ISO 8859-1 (ISO Latin1)), it MUST
|
||||
convert the password to ISO-10646 UTF-8 before transmitting, and
|
||||
the server MUST convert the password to the encoding used on that
|
||||
system for passwords.
|
||||
|
||||
Note that even though the cleartext password is transmitted in the
|
||||
packet, the entire packet is encrypted by the transport layer.
|
||||
Both the server and the client should check whether the underlying
|
||||
transport layer provides confidentiality (i.e., if encryption is
|
||||
being used). If no confidentiality is provided (none cipher),
|
||||
password authentication SHOULD be disabled. If there is no
|
||||
confidentiality or no MAC, password change SHOULD be disabled.
|
||||
|
||||
Normally, the server responds to this message with success or
|
||||
failure. However, if the password has expired the server SHOULD
|
||||
indicate this by responding with
|
||||
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. In anycase the server MUST NOT
|
||||
allow an expired password to be used for authentication.
|
||||
|
||||
byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
|
||||
string prompt (ISO-10646 UTF-8)
|
||||
string language tag (as defined in [RFC1766])
|
||||
|
||||
In this case, the client MAY continue with a different
|
||||
authentication method, or request a new password from the user and
|
||||
retry password authentication using the following message. The
|
||||
client MAY also send this message instead of the normal password
|
||||
authentication request without the server asking for it.
|
||||
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service
|
||||
string "password"
|
||||
boolean TRUE
|
||||
string plaintext old password (ISO-10646 UTF-8)
|
||||
string plaintext new password (ISO-10646 UTF-8)
|
||||
|
||||
The server must reply to request message with
|
||||
SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another
|
||||
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. The meaning of these is as
|
||||
follows:
|
||||
|
||||
SSH_MSG_USERAUTH_SUCCESS The password has been changed, and
|
||||
authentication has been successfully completed.
|
||||
|
||||
SSH_MSG_USERAUTH_FAILURE with partial success The password has
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 10]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
been changed, but more authentications are needed.
|
||||
|
||||
SSH_MSG_USERAUTH_FAILURE without partial success The password
|
||||
has not been changed. Either password changing was not
|
||||
supported, or the old password was bad. Note that if the
|
||||
server has already sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, we
|
||||
know that it supports changing the password.
|
||||
|
||||
SSH_MSG_USERAUTH_CHANGEREQ The password was not changed because
|
||||
the new password was not acceptable (e.g. too easy to guess).
|
||||
|
||||
The following method-specific message numbers are used by the
|
||||
password authentication method.
|
||||
|
||||
#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||
|
||||
|
||||
6. Host-Based Authentication: hostbased
|
||||
|
||||
Some sites wish to allow authentication based on the host where
|
||||
the user is coming from, and the user name on the remote host.
|
||||
While this form of authentication is not suitable for high-
|
||||
security sites, it can be very convenient in many environments.
|
||||
This form of authentication is OPTIONAL. When used, special care
|
||||
SHOULD be taken to prevent a regular user from obtaining the
|
||||
private host key.
|
||||
|
||||
The client requests this form of authentication by sending the
|
||||
following message. It is similar to the UNIX "rhosts" and
|
||||
"hosts.equiv" styles of authentication, except that the identity
|
||||
of the client host is checked more rigorously.
|
||||
|
||||
This method works by having the client send a signature created
|
||||
with the private key of the client host, which the server checks
|
||||
with that host's public key. Once the client host's identity is
|
||||
established, authorization (but no further authentication) is
|
||||
performed based on the user names on the server and the client,
|
||||
and the client host name.
|
||||
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service
|
||||
string "hostbased"
|
||||
string public key algorithm for host key
|
||||
string public host key and certificates for client host
|
||||
string client host name (FQDN; US-ASCII)
|
||||
string user name on the client host (ISO-10646 UTF-8)
|
||||
string signature
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 11]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
Public key algorithm names for use in "public key algorithm for
|
||||
host key" are defined in the transport layer specification. The
|
||||
"public host key for client host" may include certificates.
|
||||
|
||||
Signature is a signature with the private host key of the
|
||||
following data, in this order:
|
||||
|
||||
string session identifier
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service
|
||||
string "hostbased"
|
||||
string public key algorithm for host key
|
||||
string public host key and certificates for client host
|
||||
string client host name (FQDN; US-ASCII)
|
||||
string user name on the client host(ISO-10646 UTF-8)
|
||||
|
||||
The server MUST verify that the host key actually belongs to the
|
||||
client host named in the message, that the given user on that host
|
||||
is allowed to log in, and that the signature is a valid signature
|
||||
on the appropriate value by the given host key. The server MAY
|
||||
ignore the client user name, if it wants to authenticate only the
|
||||
client host.
|
||||
|
||||
It is RECOMMENDED that whenever possible, the server perform
|
||||
additional checks to verify that the network address obtained from
|
||||
the (untrusted) network matches the given client host name. This
|
||||
makes exploiting compromised host keys more difficult. Note that
|
||||
this may require special handling for connections coming through a
|
||||
firewall.
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
The purpose of this protocol is to perform client user
|
||||
authentication. It assumed that this runs over a secure transport
|
||||
layer protocol, which has already authenticated the server
|
||||
machine, established an encrypted communications channel, and
|
||||
computed a unique session identifier for this session. The
|
||||
transport layer provides forward secrecy for password
|
||||
authentication and other methods that rely on secret data.
|
||||
|
||||
Full security considerations for this protocol are provided in
|
||||
Section 8 of [SSH-ARCH]
|
||||
|
||||
8. Intellectual Property
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
intellectual property or other rights that might be claimed to
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 12]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
pertain to the implementation or use of the technology described
|
||||
in this document or the extent to which any license under such
|
||||
rights might or might not be available; neither does it represent
|
||||
that it has made any effort to identify any such rights.
|
||||
Information on the IETF's procedures with respect to rights in
|
||||
standards-track and standards-related documentation can be found
|
||||
in BCP-11. Copies of claims of rights made available for
|
||||
publication and any assurances of licenses to be made available,
|
||||
or the result of an attempt made to obtain a general license or
|
||||
permission for the use of such proprietary rights by implementers
|
||||
or users of this specification can be obtained from the IETF
|
||||
Secretariat.
|
||||
|
||||
The IETF has been notified of intellectual property rights claimed
|
||||
in regard to some or all of the specification contained in this
|
||||
document. For more information consult the online list of claimed
|
||||
rights.
|
||||
|
||||
9. Additional Information
|
||||
|
||||
The current document editor is: Darren.Moffat@Sun.COM. Comments
|
||||
on this internet draft should be sent to the IETF SECSH working
|
||||
group, details at: http://ietf.org/html.charters/secsh-
|
||||
charter.html
|
||||
|
||||
References
|
||||
|
||||
[RFC1766] Alvestrand, H., "Tags for the Identification of
|
||||
Languages", RFC 1766, March 1995.
|
||||
|
||||
[RFC2279] Yergeau, F., "UTF-8, a transformation format of
|
||||
ISO 10646", RFC 2279, January 1998.
|
||||
|
||||
[SSH-ARCH] Ylonen, T., "SSH Protocol Architecture", I-D
|
||||
draft-ietf-architecture-14.txt, July 2003.
|
||||
|
||||
[SSH-TRANS] Ylonen, T., "SSH Transport Layer Protocol", I-D
|
||||
draft-ietf-transport-16.txt, July 2003.
|
||||
|
||||
[SSH-USERAUTH] Ylonen, T., "SSH Authentication Protocol", I-D
|
||||
draft-ietf-userauth-17.txt, July 2003.
|
||||
|
||||
[SSH-CONNECT] Ylonen, T., "SSH Connection Protocol", I-D draft-
|
||||
ietf-connect-17.txt, July 2003.
|
||||
|
||||
[SSH-NUMBERS] Lehtinen, S. and D. Moffat, "SSH Protocol Assigned
|
||||
Numbers", I-D draft-ietf-secsh-assignednumbers-
|
||||
03.txt, July 2003.
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 13]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Tatu Ylonen
|
||||
SSH Communications Security Corp
|
||||
Fredrikinkatu 42
|
||||
HELSINKI FIN-00100
|
||||
Finland
|
||||
|
||||
EMail: ylo@ssh.com
|
||||
|
||||
|
||||
Tero Kivinen
|
||||
SSH Communications Security Corp
|
||||
Fredrikinkatu 42
|
||||
HELSINKI FIN-00100
|
||||
Finland
|
||||
|
||||
EMail: kivinen@ssh.com
|
||||
|
||||
|
||||
Markku-Juhani O. Saarinen
|
||||
University of Jyvaskyla
|
||||
|
||||
|
||||
Timo J. Rinne
|
||||
SSH Communications Security Corp
|
||||
Fredrikinkatu 42
|
||||
HELSINKI FIN-00100
|
||||
Finland
|
||||
|
||||
EMail: tri@ssh.com
|
||||
|
||||
|
||||
Sami Lehtinen
|
||||
SSH Communications Security Corp
|
||||
Fredrikinkatu 42
|
||||
HELSINKI FIN-00100
|
||||
Finland
|
||||
|
||||
EMail: sjl@ssh.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 14]
|
||||
|
||||
Internet-Draft SSH Authentication Protocol September 2002
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2002). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished
|
||||
to others, and derivative works that comment on or otherwise
|
||||
explain it or assist in its implementation may be prepared,
|
||||
copied, published and distributed, in whole or in part, without
|
||||
restriction of any kind, provided that the above copyright notice
|
||||
and this paragraph are included on all such copies and derivative
|
||||
works. However, this document itself may not be modified in any
|
||||
way, such as by removing the copyright notice or references to the
|
||||
Internet Society or other Internet organizations, except as needed
|
||||
for the purpose of developing Internet standards in which case the
|
||||
procedures for copyrights defined in the Internet Standards
|
||||
process must be followed, or as required to translate it into
|
||||
languages other than English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not
|
||||
be revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on
|
||||
an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET
|
||||
ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
|
||||
THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is currently provided by the
|
||||
Internet Society.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Ylonen, et. al. Expires March 2, 2003 [Page 15]
|
||||
|
370
doc/libssh-0.2-api-1.txt
Обычный файл
370
doc/libssh-0.2-api-1.txt
Обычный файл
@ -0,0 +1,370 @@
|
||||
The new libssh 0.2 API
|
||||
----------------------
|
||||
|
||||
Version 1
|
||||
|
||||
A. Introduction
|
||||
---------------
|
||||
|
||||
With the time from the first release of libssh, I have received lots of
|
||||
comments about the current API. Myself, I found it quite limiting when doing
|
||||
my first libssh-server drafts. Thus, I am moving to a stronger API.
|
||||
This API must still be simple. I am not introducing complex changes. An API
|
||||
well designed must hide the implementation details. Implementation can change
|
||||
easily within bugfixes - but API cannot change each release.
|
||||
|
||||
To the people already using libssh 0.11 : sorry. Once I have the complete API
|
||||
redesigned, I will write a migration paper. It won't be too hard normally.
|
||||
|
||||
Here are the things that were lacking in the previous API and *must* change:
|
||||
|
||||
* A non-blocking mode connection type
|
||||
* Functions to relegate File descriptor listening to Calling functions and to
|
||||
the programmer. (I'll explain later).
|
||||
* Along with that, good buffering system (well, it's not an API but).
|
||||
* Leave the "functions returns a pointer when it works and NULL when it does
|
||||
not work". It gives serious problems to implement bindings (A C++
|
||||
constructor should not fail and should not depend on a network thing
|
||||
* Make the Session structure an abstract structure that can work with both
|
||||
client and *servers*. That mean we should have a Server object which listen
|
||||
to clients on a bound port, does the different handshakes and return a
|
||||
session.
|
||||
Since C is not per se an Object language, I won't use inheritance between
|
||||
objects.
|
||||
* This same server thing must provide the reverse capabilities than the
|
||||
client. That is, accept the handshake, in a nonblocking way. Accept channel
|
||||
requests, or send them to the controller program.
|
||||
* Support for program forking : Imagine you have a Ssh server object. You
|
||||
accept a connection and receive a session, then you receive a channel. You
|
||||
may want to keep the good old days fork() tricks. Libssh will give a way to
|
||||
destroy handlers from sessions which belong to an other process without
|
||||
disturbing the session.
|
||||
* So often I received the comment back saying that it was not clear why a
|
||||
session or a channel was terminated. This is over.
|
||||
* And of course I received lot of mails about the fact I'm doing namespace
|
||||
polution. this will be resolved this time.
|
||||
So, please read this draft not as a formal documentation but like a roadmap of
|
||||
things that each kind of object must do.
|
||||
|
||||
B. Description of objects and functions
|
||||
|
||||
Options structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
struct ssh_options *ssh_options_new()
|
||||
|
||||
ssh_options_getopt(options, *argc, argv)
|
||||
|
||||
ssh_options_copy(options)
|
||||
|
||||
char ** ssh_options_get_supported_algos(options,type)
|
||||
returns a list of the algos supported by libssh, type being one of
|
||||
SSH_HOSTKEYS, SSH_KEX, SSH_CRYPT, SSH_MAC, SSH_COMP, SSH_LANG
|
||||
|
||||
ssh_options_set_wanted_algos(options,type, char *list)
|
||||
list being comma-separated list of algos, and type being the upper constants
|
||||
but with _C_S or _S_V added to them.
|
||||
|
||||
ssh_options_set_port(options, port)
|
||||
|
||||
ssh_options_set_host(options, host)
|
||||
|
||||
ssh_options_set_fd(options, fd)
|
||||
|
||||
ssh_options_set_bind(options, bindaddr, port)
|
||||
this options sets the address to bind for a client *or* a server. a port of
|
||||
zero means whatever port is free (what most clients want).
|
||||
|
||||
ssh_options_set_username(options, username)
|
||||
|
||||
ssh_options_set_connect_timeout(options, seconds, usec)
|
||||
|
||||
ssh_options_set_ssh_dir(options, dir)
|
||||
ssh_options_set_known_hosts_file(options, file)
|
||||
ssh_options_set_identity(options, file)
|
||||
|
||||
ssh_options_set_banner(options, banner)
|
||||
ssh_options_allow_ssh1(options, bool allow)
|
||||
ssh_options_allow_ssh2(options, bool allow)
|
||||
|
||||
options_set_status_callback has moved into ssh_* functions.
|
||||
|
||||
ssh_session Structure
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This session structure represents a ssh socket to a server *or* a client.
|
||||
|
||||
ssh_session *ssh_new()
|
||||
|
||||
ssh_set_options(ssh_session,ssh_options)
|
||||
|
||||
ssh_connect(session);
|
||||
it will return some status describing at which point of the connection it is,
|
||||
or an error code. If the connection method is non-blocking, the function
|
||||
will be called more than once, though the return value SSH_AGAIN.
|
||||
|
||||
ssh_set_blocking(session, bool blocking)
|
||||
set blocking mode or non blocking mode.
|
||||
|
||||
ssh_get_fd(session)
|
||||
get the currently used connection file descriptor or equivalent (windows)
|
||||
|
||||
ssh_set_fd_toread(session)
|
||||
ssh_set_fd_towrite(session)
|
||||
ssh_set_fd_except(session)
|
||||
Serve to notify the library that data is actualy available to be read on the
|
||||
file descriptor socket. why ? because on most platforms select can't be done
|
||||
twice on the same socket when the first reported data to read or to write
|
||||
|
||||
ssh_get_status(session)
|
||||
Returns the current status bitmask : connection Open or closed, data
|
||||
pending to read or not (even if connection closed), connection closed on
|
||||
error or on an exit message
|
||||
|
||||
ssh_get_disconnect_message(session)
|
||||
Returns the connection disconnect error/exit message
|
||||
|
||||
ssh_get_pubkey_hash(session, hash)
|
||||
get the public key hash from the server.
|
||||
|
||||
ssh_is_server_known(session)
|
||||
ssh_write_knownhost(session)
|
||||
these 2 functions will be kept
|
||||
|
||||
ssh_disconnect(session)
|
||||
standard disconnect
|
||||
|
||||
ssh_disconnect_error(session,error code, message)
|
||||
disconnect with a message
|
||||
|
||||
ssh_set_username(session)
|
||||
set the user name to log in
|
||||
|
||||
ssh_userauth_* functions will be kept as they are now, excepted the fact that
|
||||
the username field will disapear.
|
||||
the public key mechanism may get some more functions, like retrieving a public
|
||||
key from a private key and authenticating without a public key.
|
||||
|
||||
ssh_get_issue_banner(session)
|
||||
get the issue banner from the server, that is the welcome message.
|
||||
|
||||
ssh_silent_free(session)
|
||||
This function silently free all data structures used by the session and
|
||||
closes the socket. It may be used for instance when the process forked and
|
||||
doesn't want to keep track of this session. This is obviously not possible to
|
||||
do with separate channels.
|
||||
|
||||
The channel_struct structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The channels will change a bit. the constructor thing will change, and the way
|
||||
to multiplex different connections will change too. channel functions will be
|
||||
prefixed with "ssh_"
|
||||
|
||||
struct channel_struct *ssh_channel_new()
|
||||
|
||||
ssh_channel_open_session(channel)
|
||||
will return if the channel allocation failed or not.
|
||||
|
||||
ssh_channel_open_forward(channel, ...) won't change. it will report an error if
|
||||
the channel allocation failed.
|
||||
|
||||
ssh_channel_send_eof(channel)
|
||||
send EOF
|
||||
ssh_channel_close(channel)
|
||||
closes a channel but doesn't destroy it. you may read unread data still in
|
||||
the buffer. Once you closed the buffer, the other party can't send you data,
|
||||
while it could still do it if you only sent an EOF.
|
||||
ssh_channel_is_closed(channel)
|
||||
returns true if the channel was closed at one of both sides. a closed chan
|
||||
may still have data to read, if you closed yourself the connection. otherwise
|
||||
(you didn't close it) the closed notification only comes when you read the
|
||||
last buffer byte, or when trying to write into the channel (the SIGPIPE-like
|
||||
behaviour).
|
||||
|
||||
ssh_channel_is_eof(channel)
|
||||
reports if the other side has sent an EOF. This functions returns FALSE if
|
||||
there is still data to read. A closed channel is always EOF.
|
||||
ssh_channel_free(channel)
|
||||
completely free the channel. closes it before if it was not done.
|
||||
|
||||
ssh_channel_request_env(channel, name, value)
|
||||
set an environment variable.
|
||||
|
||||
ssh_channel_request_pty(channel)
|
||||
ssh_channel_request_pty_size()
|
||||
ssh_channel_change_pty_size()
|
||||
ssh_channel_request_shell()
|
||||
ssh_channel_request_exec()
|
||||
ssh_channel_request_subsystem()
|
||||
These functions won't change.
|
||||
|
||||
int ssh_channel_write(channel,data, len,stderr)
|
||||
Depending on the blocking/non blocking mode of the channel, the behaviour may
|
||||
change.
|
||||
stderr is the extended buffer. It's generaly only a server->client stream.
|
||||
|
||||
ssh_channel_set_blocking(bool blocking)
|
||||
|
||||
int ssh_channel_read(channel, buffer, maxlen, is_stderr)
|
||||
the behaviour will be this one:
|
||||
-if the chan is in non blocking mode, it will poll what's available to read
|
||||
and return this. otherwise (nothing to read) it will return 0.
|
||||
-if the chan is blocking, it will block until at least one byte is
|
||||
available.
|
||||
ssh_channel_nonblocking disapears for the later reason.
|
||||
|
||||
int channel_poll(channel, is_stderr)
|
||||
polls the network and reports the number of bytes ready to be read in the
|
||||
chan.
|
||||
|
||||
ssh_session ssh_channel_get_session(channel)
|
||||
returns the session pointer associated to the channel, for simplicity
|
||||
reasons.
|
||||
|
||||
int ssh_channel_select(CHANNELS *readchans, CHANNELS *writechans, CHANNELS
|
||||
*exceptchans, struct timeval *timeout)
|
||||
This function won't work the same way ssh_select did.
|
||||
I removed the custom file descriptor thing for 2 reasons:
|
||||
1- it's not windows compliant. D'ouh !
|
||||
2- most programmers won't want to depend on libssh for socket multiplexing.
|
||||
that's why i let the programmer poll the fds himself and then use
|
||||
ssh_set_fd_toread, towrite or except. Then, he may use ssh_channel_select
|
||||
with a NULL timeout to poll which channels have something to read, write or
|
||||
error report.
|
||||
Here is how it's going to work. The coder sets 3 different arrays with the
|
||||
channels he wants to select(), the last entry being a NULL pointer. The
|
||||
function will first poll them and return the chans that must be
|
||||
read/write/excepted. If nothing has this state, the function will select()
|
||||
using the timeout.
|
||||
The function will return 0 if everything is ok, SSH_TIMEOUT or SSH_EINTR if
|
||||
the select was interrupted by a signal. It is dangerous to execute any
|
||||
channel-related functions into signal handlers. they should set a flag that
|
||||
you read into your loop. this "trap" (SSH_EINTR) will permit you to catch
|
||||
them faster and make your program responsive and look fast.
|
||||
the function will return -1 if a serious problem happens.
|
||||
|
||||
|
||||
Error handling
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
when an error happens, the programmer can get the error code and description
|
||||
with ssh_get_error(session). the creation of a failess constructor for
|
||||
ssh_session was needed for this reason.
|
||||
|
||||
ssh_get_error_code(session) will return an error code into this subset:
|
||||
SSH_NO_ERROR : no error :)
|
||||
SSH_REQUEST_DENIED : you request for a functionality or a service that is not
|
||||
allowed. The session can continue.
|
||||
SSH_FATAL : Unrecoverable error. The session can't continue and you should
|
||||
disconnect the session. It includes the connection being cut without a
|
||||
disconnect() message.
|
||||
If a disconnect() message or the channel was closed, a read on such a channel
|
||||
won't produce an error. otherwise it will return -1 with a SSH_FATAL error
|
||||
code.
|
||||
|
||||
Server socket binding
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It is not possible to bind a socket for ssh with a SSH_SESSION type, because a
|
||||
single bound port may lead to multiple ssh connections. That's why the
|
||||
SSH_BIND structure must be created. It uses options from the SSH_OPTIONS
|
||||
structure.
|
||||
|
||||
SSH_BIND *ssh_bind_new()
|
||||
creates a structure
|
||||
ssh_bind_set_options(bind, options)
|
||||
set the option structure
|
||||
int ssh_bind_listen(bind)
|
||||
bind and listen to the port. This call is not blocking. if some error
|
||||
happens, it returns -1 and the error code can be found with perror().
|
||||
|
||||
ssh_bind_set_blocking(bind, bool blocking)
|
||||
should ssh_bind_accept() block or not.
|
||||
|
||||
int ssh_bind_get_fd(bind)
|
||||
return the bound file descriptor, that is the listener socket. you may put it
|
||||
into a select() in your code to detect a connection attempt.
|
||||
|
||||
ssh_bind_set_fd_toaccept(bind)
|
||||
say that the listener socket has a connection to accept (to avoid
|
||||
ssh_bind_accept() to do a select on it).
|
||||
|
||||
SSH_SESSION *ssh_bind_accept(bind)
|
||||
return a server handle to a ssh session. if the mode is blocking, the
|
||||
function will always return a pointer to a session. if the mode is not
|
||||
blocking, the function can return NULL if there is no connection to accept.
|
||||
|
||||
This SSH_SESSION handle must then pass through the functions explained above.
|
||||
|
||||
|
||||
*server functions *
|
||||
|
||||
int ssh_accept(session)
|
||||
when a new connection is accepted, the handshake must be done. this function
|
||||
will do the banner handshake and the key exchange.
|
||||
it will return SSH_AGAIN if the session mode is non blocking, and the
|
||||
function must be called again until an error occurs or the kex is done.
|
||||
|
||||
Here, I had a few choises about *how* to implement the message parsing as a
|
||||
server. There are multiple ways to do it, one being callbacks and one being
|
||||
"Message" reading, parsing and then choice going to the user to use it and
|
||||
answer. I've choosen the latter because i believe it's the stronger method.
|
||||
A ssh server can receive 30 different kind of messages having to be dealt by
|
||||
the high level routines, like channel request_shell or authentication. Having
|
||||
a callback for all of them would produce a huge kludge of callbacks, with
|
||||
no relations on when there were called etc.
|
||||
A message based parsing allows the user to filtrate the messages he's
|
||||
interested into and to use a default answer for the others. Then, the callback
|
||||
thing is still possible to handle through a simple message code/callback
|
||||
function array.
|
||||
|
||||
I did not define yet what it would look like, but i'm sure there will be a
|
||||
SSH_MESSAGE (they won't have a 1/1 correspondance with ssh packets) which will
|
||||
be read through
|
||||
SSH_MESSAGE *ssh_server_read_message(session).
|
||||
with all of the non-blocking stuff in head like returning NULL if the message
|
||||
is not full.
|
||||
Then, the message can be parsed, ie
|
||||
int ssh_message_get_code(message)
|
||||
which will return SSH_MESSAGE_AUTH
|
||||
then
|
||||
int ssh_message_get_subcode(message)
|
||||
which then will returh SSH_MESSAGE_AUTH_PASSWORD or _NONE or _PUBKEY etc.
|
||||
|
||||
Then, once the message was parsed, the message will have to be answered, ie
|
||||
with the generic functions like
|
||||
ssh_message_accept(message) which says 'Ok your request is accepted' or
|
||||
ssh_message_deny(message) which says 'Your request is refused'.
|
||||
|
||||
There would be specific message answer functions for some kind of messages
|
||||
like the authentication one. you may want to reply that the authentication is
|
||||
Partial rather than denied, and that you still accept some kind of auths, like
|
||||
ssh_message_auth_reply(message,SSH_AUTH_PARTIAL,SSH_AUTH_PASSWORD |
|
||||
SSH_AUTH_PUBKEY | SSH_AUTH_KEYBINT);
|
||||
|
||||
I won't let the user have to deal with the channels himself. When a channel is
|
||||
going to be created by the remote size, a message will come asking to open a
|
||||
channel. the programmer can either deny or accept, in which case a CHANNEL
|
||||
object will be created and returned to the programmer. then, all standard
|
||||
channel functions will run.
|
||||
|
||||
C. Change log of this document
|
||||
|
||||
2. ssh_options_set_username finaly is kept into the options, because it can be
|
||||
set by ssh_options_getopt()
|
||||
|
||||
1. first release
|
||||
|
||||
D. End notes
|
||||
|
||||
I think libssh must have a very simple to use, powerful and exhaustive API. It
|
||||
must have no design flaw either.
|
||||
While I got some good experience at the SSH protocol, I've never writen
|
||||
more-than-100 lines programs than use libssh and I don't really know the
|
||||
problems of the library. I'd like people who don't understand some detail into
|
||||
the API I describe here, who have comments or opinions about it to write me
|
||||
the soonest possible to limit the damages if I made something the completely
|
||||
wrong way.
|
||||
Thanks for your patience.
|
||||
|
1501
doc/protocol-1.5.txt
Обычный файл
1501
doc/protocol-1.5.txt
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
184
doc/style.css
Обычный файл
184
doc/style.css
Обычный файл
@ -0,0 +1,184 @@
|
||||
|
||||
body {
|
||||
background-color:#ddf;
|
||||
/*background-image:url(../back6.jpg);*/
|
||||
margin:10px 10px 10px 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:80%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-align:left;
|
||||
}
|
||||
h2 {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:100%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-align:left;
|
||||
}
|
||||
h3 {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:80%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-align:left;
|
||||
}
|
||||
p {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:80%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-align:left;
|
||||
margin-left:0px;
|
||||
margin-right:0px;
|
||||
}
|
||||
li {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:80%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-align:left;
|
||||
margin-left:0px;
|
||||
margin-right:0px;
|
||||
}
|
||||
a:link {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:100%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-decoration:underline;
|
||||
}
|
||||
a:visited {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:100%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-decoration:underline;
|
||||
}
|
||||
a:hover {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:100%;
|
||||
color:black;
|
||||
background-color:transparent;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
table {
|
||||
border-color:transparent;
|
||||
border-style:solid;
|
||||
border-width:1px;
|
||||
}
|
||||
|
||||
td {
|
||||
font-family:verdana, sans-serif;
|
||||
font-size:80%;
|
||||
color:black;
|
||||
text-align:left;
|
||||
background-color:transparent;
|
||||
border-color:transparent;
|
||||
border-style:solid;
|
||||
border-width:1px;
|
||||
}
|
||||
|
||||
.tout {
|
||||
margin: 5px;
|
||||
padding: 0px;
|
||||
border: 2px solid #aac;
|
||||
background: #eef;
|
||||
}
|
||||
|
||||
.prot {
|
||||
border-style:solid;
|
||||
border-width:2px;
|
||||
border-color:#88F;
|
||||
padding: 4px;
|
||||
background-color:#cce;
|
||||
margin: 5px 5px 5px 5px;
|
||||
}
|
||||
|
||||
.ex {
|
||||
border-style:solid;
|
||||
border-width:2px;
|
||||
border-color:#aaF;
|
||||
padding: 4px;
|
||||
background-color:#dde;
|
||||
margin: 5px 5px 5px 5px;
|
||||
}
|
||||
.desc {
|
||||
border-style:solid;
|
||||
border-width:3px;
|
||||
border-color:#66F;
|
||||
padding: 4px;
|
||||
background-color:#aac;
|
||||
margin: 15px 5px 20px 5px;
|
||||
}
|
||||
|
||||
#titre {
|
||||
margin: 5px;
|
||||
padding: 0px;
|
||||
border: 5px solid #aac;
|
||||
background: #eef;
|
||||
}
|
||||
|
||||
#gauche {
|
||||
float:left;
|
||||
margin: 5px;
|
||||
padding: 4px;
|
||||
border: 5px solid #aac;
|
||||
background: #bbf;
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
#droite {
|
||||
position: relative;
|
||||
top:5px;
|
||||
left:165px;
|
||||
margin: 5px 170px 5px 5px;
|
||||
padding: 10px;
|
||||
border: 5px solid #aac;
|
||||
background: #bbf;
|
||||
}
|
||||
|
||||
/* boutons */
|
||||
|
||||
a.bouton:link{
|
||||
width:128px;
|
||||
height:34px;
|
||||
text-decoration:none;
|
||||
color:#aaa;
|
||||
text-align:center;
|
||||
font-weight:bold;
|
||||
/*background-color:#444;*/
|
||||
background-image:url(noclicked.png);
|
||||
}
|
||||
|
||||
a.bouton:visited{
|
||||
width:128px;
|
||||
height:34px;
|
||||
text-decoration:none;
|
||||
color:#aaa;
|
||||
text-align:center;
|
||||
font-weight:bold;
|
||||
/*background-color:#444;*/
|
||||
background-image:url(noclicked.png);
|
||||
}
|
||||
|
||||
a.bouton:hover{
|
||||
width:128px;
|
||||
height:34px;
|
||||
text-decoration:none;
|
||||
color:white;
|
||||
text-align:center;
|
||||
font-weight:bold;
|
||||
/*background-color:#888;*/
|
||||
background-image:url(clicked.png);
|
||||
}
|
||||
|
||||
.bouton{
|
||||
text-align:center;
|
||||
display:block;
|
||||
}
|
||||
|
1
include/libssh/config.h
Символическая ссылка
1
include/libssh/config.h
Символическая ссылка
@ -0,0 +1 @@
|
||||
../../config.h
|
47
include/libssh/crypto.h
Обычный файл
47
include/libssh/crypto.h
Обычный файл
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
/* Crypto.h is an include file for internal structures of libssh */
|
||||
/* It hasn't to be into the final development set of files (and btw the filename would cause problems on most systems) */
|
||||
/* Openssl has (really) stupid defines */
|
||||
#ifdef set_key
|
||||
#undef set_key
|
||||
#endif
|
||||
#ifdef cbc_encrypt
|
||||
#undef cbc_encrypt
|
||||
#endif
|
||||
#ifdef cbc_decrypt
|
||||
#undef cbc_decrypt
|
||||
#endif
|
||||
#ifdef des_set_key
|
||||
#undef des_set_key
|
||||
#endif
|
||||
struct crypto_struct {
|
||||
char *name; /* ssh name of the algorithm */
|
||||
unsigned int blocksize; /* blocksize of the algo */
|
||||
unsigned int keylen; /* length of the key structure */
|
||||
void *key; /* a key buffer allocated for the algo */
|
||||
unsigned int keysize; /* bytes of key used. != keylen */
|
||||
void (*set_encrypt_key)(struct crypto_struct *cipher, void *key); /* sets the new key for immediate use */
|
||||
void (*set_decrypt_key)(struct crypto_struct *cipher, void *key);
|
||||
void (*cbc_encrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV);
|
||||
void (*cbc_decrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV);
|
||||
};
|
||||
|
234
include/libssh/libssh.h
Обычный файл
234
include/libssh/libssh.h
Обычный файл
@ -0,0 +1,234 @@
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _LIBSSH_H
|
||||
#define _LIBSSH_H
|
||||
#include <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
Обычный файл
444
include/libssh/priv.h
Обычный файл
@ -0,0 +1,444 @@
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
/* priv.h file */
|
||||
/* This include file contains everything you shouldn't deal with in user programs. */
|
||||
/* Consider that anything in this file might change without notice; libssh.h file will keep */
|
||||
/* backward compatibility on binary & source */
|
||||
|
||||
#ifndef _LIBSSH_PRIV_H
|
||||
#define _LIBSSH_PRIV_H
|
||||
#include "libssh/libssh.h"
|
||||
|
||||
/* Debugging constants */
|
||||
|
||||
/* Define this if you want to debug crypto systems */
|
||||
/* it's usefull when you are debugging the lib */
|
||||
/*#define DEBUG_CRYPTO */
|
||||
|
||||
/* some constants */
|
||||
#define MAX_PACKET_LEN 262144
|
||||
#define ERROR_BUFFERLEN 1024
|
||||
#define CLIENTBANNER1 "SSH-1.5-" LIBSSH_VERSION
|
||||
#define CLIENTBANNER2 "SSH-2.0-" LIBSSH_VERSION
|
||||
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
|
||||
/* some types for public keys */
|
||||
#define TYPE_DSS 1
|
||||
#define TYPE_RSA 2
|
||||
#define TYPE_RSA1 3
|
||||
|
||||
/* profiling constants. Don't touch them unless you know what you do */
|
||||
#define OPENSSL_CRYPTO
|
||||
#define OPENSSL_BIGNUMS
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* wrapper things */
|
||||
|
||||
#ifdef OPENSSL_CRYPTO
|
||||
#include <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
Обычный файл
31
include/libssh/server.h
Обычный файл
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2004 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
/* the client banner doesn't say hey! look i'm a client ! */
|
||||
#include "libssh/libssh.h"
|
||||
#define SERVERBANNER CLIENTBANNER
|
||||
|
||||
int bind_socket();
|
||||
int listen_socket(int s);
|
||||
int accept_socket(int s);
|
||||
|
||||
#endif
|
225
include/libssh/sftp.h
Обычный файл
225
include/libssh/sftp.h
Обычный файл
@ -0,0 +1,225 @@
|
||||
/* sftp headers */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#ifndef SFTP_H
|
||||
#define SFTP_H
|
||||
#include <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
Обычный файл
82
include/libssh/ssh1.h
Обычный файл
@ -0,0 +1,82 @@
|
||||
#ifndef __SSH1_H
|
||||
#define __SSH1_H
|
||||
|
||||
#define SSH_MSG_NONE 0 /* no message */
|
||||
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
|
||||
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
|
||||
#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
|
||||
#define SSH_CMSG_USER 4 /* user (string) */
|
||||
#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
|
||||
#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
|
||||
#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
|
||||
#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
|
||||
#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
|
||||
#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
|
||||
#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
|
||||
#define SSH_CMSG_EXEC_SHELL 12 /* */
|
||||
#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
|
||||
#define SSH_SMSG_SUCCESS 14 /* */
|
||||
#define SSH_SMSG_FAILURE 15 /* */
|
||||
#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
|
||||
#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
|
||||
#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
|
||||
#define SSH_CMSG_EOF 19 /* */
|
||||
#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
|
||||
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
|
||||
#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
|
||||
/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
|
||||
#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
|
||||
#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
|
||||
#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
|
||||
#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
|
||||
#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
|
||||
#define SSH_MSG_IGNORE 32 /* string */
|
||||
#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
|
||||
#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
|
||||
#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
|
||||
#define SSH_MSG_DEBUG 36 /* string */
|
||||
#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
|
||||
#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
|
||||
#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
|
||||
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
|
||||
#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
|
||||
#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
|
||||
#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
|
||||
#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
|
||||
#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
|
||||
|
||||
/* protocol version 1.5 overloads some version 1.3 message types */
|
||||
#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE
|
||||
#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
|
||||
|
||||
/*
|
||||
* Authentication methods. New types can be added, but old types should not
|
||||
* be removed for compatibility. The maximum allowed value is 31.
|
||||
*/
|
||||
#define SSH_AUTH_RHOSTS 1
|
||||
#define SSH_AUTH_RSA 2
|
||||
#define SSH_AUTH_PASSWORD 3
|
||||
#define SSH_AUTH_RHOSTS_RSA 4
|
||||
#define SSH_AUTH_TIS 5
|
||||
#define SSH_AUTH_KERBEROS 6
|
||||
#define SSH_PASS_KERBEROS_TGT 7
|
||||
/* 8 to 15 are reserved */
|
||||
#define SSH_PASS_AFS_TOKEN 21
|
||||
|
||||
/* Protocol flags. These are bit masks. */
|
||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
|
||||
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
|
||||
|
||||
/* cipher flags. they are bit numbers */
|
||||
#define SSH_CIPHER_NONE 0 /* No encryption */
|
||||
#define SSH_CIPHER_IDEA 1 /* IDEA in CFB mode */
|
||||
#define SSH_CIPHER_DES 2 /* DES in CBC mode */
|
||||
#define SSH_CIPHER_3DES 3 /* Triple-DES in CBC mode */
|
||||
#define SSH_CIPHER_RC4 5 /* RC4 */
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
|
||||
#endif
|
||||
|
69
include/libssh/ssh2.h
Обычный файл
69
include/libssh/ssh2.h
Обычный файл
@ -0,0 +1,69 @@
|
||||
#ifndef __SSH2_H
|
||||
#define __SSH2_H
|
||||
|
||||
#define SSH2_MSG_DISCONNECT 1
|
||||
#define SSH2_MSG_IGNORE 2
|
||||
#define SSH2_MSG_UNIMPLEMENTED 3
|
||||
#define SSH2_MSG_DEBUG 4
|
||||
#define SSH2_MSG_SERVICE_REQUEST 5
|
||||
#define SSH2_MSG_SERVICE_ACCEPT 6
|
||||
|
||||
#define SSH2_MSG_KEXINIT 20
|
||||
#define SSH2_MSG_NEWKEYS 21
|
||||
|
||||
#define SSH2_MSG_KEXDH_INIT 30
|
||||
#define SSH2_MSG_KEXDH_REPLY 31
|
||||
|
||||
#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||
#define SSH2_MSG_KEX_DH_GEX_GROUP 31
|
||||
#define SSH2_MSG_KEX_DH_GEX_INIT 32
|
||||
#define SSH2_MSG_KEX_DH_GEX_REPLY 33
|
||||
#define SSH2_MSG_KEX_DH_GEX_REQUEST 34
|
||||
#define SSH2_MSG_USERAUTH_REQUEST 50
|
||||
#define SSH2_MSG_USERAUTH_FAILURE 51
|
||||
#define SSH2_MSG_USERAUTH_SUCCESS 52
|
||||
#define SSH2_MSG_USERAUTH_BANNER 53
|
||||
#define SSH2_MSG_USERAUTH_PK_OK 60
|
||||
#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||
#define SSH2_MSG_USERAUTH_INFO_REQUEST 60
|
||||
#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
|
||||
#define SSH2_MSG_GLOBAL_REQUEST 80
|
||||
#define SSH2_MSG_REQUEST_SUCCESS 81
|
||||
#define SSH2_MSG_REQUEST_FAILURE 82
|
||||
#define SSH2_MSG_CHANNEL_OPEN 90
|
||||
#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
||||
#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92
|
||||
#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
|
||||
#define SSH2_MSG_CHANNEL_DATA 94
|
||||
#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95
|
||||
#define SSH2_MSG_CHANNEL_EOF 96
|
||||
#define SSH2_MSG_CHANNEL_CLOSE 97
|
||||
#define SSH2_MSG_CHANNEL_REQUEST 98
|
||||
#define SSH2_MSG_CHANNEL_SUCCESS 99
|
||||
#define SSH2_MSG_CHANNEL_FAILURE 100
|
||||
|
||||
#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
|
||||
#define SSH2_DISCONNECT_PROTOCOL_ERROR 2
|
||||
#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3
|
||||
#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4
|
||||
#define SSH2_DISCONNECT_RESERVED 4
|
||||
#define SSH2_DISCONNECT_MAC_ERROR 5
|
||||
#define SSH2_DISCONNECT_COMPRESSION_ERROR 6
|
||||
#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7
|
||||
#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
|
||||
#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
|
||||
#define SSH2_DISCONNECT_CONNECTION_LOST 10
|
||||
#define SSH2_DISCONNECT_BY_APPLICATION 11
|
||||
#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12
|
||||
#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13
|
||||
#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
|
||||
#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15
|
||||
|
||||
#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH2_OPEN_CONNECT_FAILED 2
|
||||
#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3
|
||||
#define SSH2_OPEN_RESOURCE_SHORTAGE 4
|
||||
|
||||
#define SSH2_EXTENDED_DATA_STDERR 1
|
||||
|
||||
#endif
|
251
install-sh
Исполняемый файл
251
install-sh
Исполняемый файл
@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
chmodcmd=""
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
129
libssh.kdevelop
Обычный файл
129
libssh.kdevelop
Обычный файл
@ -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>
|
Двоичные данные
libssh.kdevelop.pcs
Обычный файл
Двоичные данные
libssh.kdevelop.pcs
Обычный файл
Двоичный файл не отображается.
29
libssh.kdevses
Обычный файл
29
libssh.kdevses
Обычный файл
@ -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
Обычный файл
44
libssh/Makefile.in
Обычный файл
@ -0,0 +1,44 @@
|
||||
|
||||
OBJECTS= client.o packet.o dh.o crypt.o connect.o error.o buffer.o \
|
||||
string.o kex.o channels.o options.o keys.o auth.o base64.o \
|
||||
keyfiles.o misc.o gzip.o wrapper.o sftp.o server.o crc32.o \
|
||||
session.o
|
||||
SHELL = /bin/sh
|
||||
VPATH = @srcdir@
|
||||
|
||||
subdirs = @subdirs@
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = $(exec_prefix)/bin
|
||||
incldir= $(prefix)/include
|
||||
infodir = $(prefix)/info
|
||||
libdir = $(prefix)/lib/
|
||||
mandir = $(prefix)/man/man1
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ -Wall -g -I../include/ -fPIC
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
INSTALL = @INSTALL@
|
||||
DYLIB_EXTENSION = @DYLIB_EXTENSION@
|
||||
LIBSSH_LDFLAGS = @LIBSSH_LDFLAGS@
|
||||
|
||||
all: libssh.so
|
||||
|
||||
libssh.so: $(OBJECTS)
|
||||
$(CC) -o libssh.$(DYLIB_EXTENSION) $(LIBSSH_LDFLAGS) $(OBJECTS) $(LIBS) $(LDFLAGS)
|
||||
libssh.a: $(OBJECTS)
|
||||
rm -f libssh.a
|
||||
ar q libssh.a $(OBJECTS)
|
||||
@RANLIB@ libssh.a
|
||||
install: all
|
||||
$(top_srcdir)/mkinstalldirs $(incldir)
|
||||
$(top_srcdir)/mkinstalldirs $(libdir)
|
||||
$(INSTALL) libssh.$(DYLIB_EXTENSION) $(libdir)
|
||||
clean:
|
||||
rm -f *~ libssh.a libssh.so *.o
|
||||
distclean: clean
|
||||
rm -f Makefile
|
||||
|
605
libssh/auth.c
Обычный файл
605
libssh/auth.c
Обычный файл
@ -0,0 +1,605 @@
|
||||
/* auth.c deals with authentication methods */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include <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
Обычный файл
210
libssh/base64.c
Обычный файл
@ -0,0 +1,210 @@
|
||||
/* base64 contains the needed support for base64 alphabet system, */
|
||||
/* as described in RFC1521 */
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
/* just the dirtiest part of code i ever made */
|
||||
#include <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
Обычный файл
181
libssh/buffer.c
Обычный файл
@ -0,0 +1,181 @@
|
||||
/* buffer.c */
|
||||
/* Well, buffers */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
701
libssh/channels.c
Обычный файл
@ -0,0 +1,701 @@
|
||||
/* channels.c */
|
||||
/* It has support for ... ssh channels */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
287
libssh/client.c
Обычный файл
@ -0,0 +1,287 @@
|
||||
/* client.c file */
|
||||
/*
|
||||
Copyright 2003-2005 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
286
libssh/connect.c
Обычный файл
@ -0,0 +1,286 @@
|
||||
/* connect.c */
|
||||
/* it handles connections to ssh servers */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
88
libssh/crc32.c
Обычный файл
@ -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
Обычный файл
105
libssh/crypt.c
Обычный файл
@ -0,0 +1,105 @@
|
||||
/* crypt.c */
|
||||
/* it just contains the shit necessary to make blowfish-cbc work ... */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
412
libssh/dh.c
Обычный файл
@ -0,0 +1,412 @@
|
||||
/* dh.c */
|
||||
/* this file contains usefull stuff for Diffie helman algorithm against SSH 2 */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
/* Let us resume the dh protocol. */
|
||||
/* Each side computes a private prime number, x at client side, y at server side. */
|
||||
/* g and n are two numbers common to every ssh software. */
|
||||
/* client's public key (e) is calculated by doing */
|
||||
/* e = g^x mod p */
|
||||
/* client sents e to the server . */
|
||||
/* the server computes his own public key, f */
|
||||
/* f = g^y mod p */
|
||||
/* it sents it to the client */
|
||||
/* the common key K is calculated by the client by doing */
|
||||
/* k = f^x mod p */
|
||||
/* the server does the same with the client public key e */
|
||||
/* k' = e^y mod p */
|
||||
/* if everything went correctly, k and k' are equal */
|
||||
|
||||
#include <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
Обычный файл
56
libssh/error.c
Обычный файл
@ -0,0 +1,56 @@
|
||||
/* error.c */
|
||||
/* it does contain error processing functions */
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
140
libssh/gzip.c
Обычный файл
@ -0,0 +1,140 @@
|
||||
/* gzip.c */
|
||||
/* include hooks for compression of packets */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
#include "libssh/priv.h"
|
||||
#ifdef HAVE_LIBZ
|
||||
#undef NO_GZIP
|
||||
#else
|
||||
#define NO_GZIP
|
||||
#endif
|
||||
|
||||
#ifndef NO_GZIP
|
||||
#include <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
Обычный файл
439
libssh/kex.c
Обычный файл
@ -0,0 +1,439 @@
|
||||
/* kex.c is used well, in key exchange :-) */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
344
libssh/keyfiles.c
Обычный файл
@ -0,0 +1,344 @@
|
||||
/* keyfiles.c */
|
||||
/* This part of the library handles private and public key files needed for publickey authentication,*/
|
||||
/* as well as servers public hashes verifications and certifications. Lot of code here handles openssh */
|
||||
/* implementations (key files aren't standardized yet). */
|
||||
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
#include <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
Обычный файл
370
libssh/keys.c
Обычный файл
@ -0,0 +1,370 @@
|
||||
/* keys handle the public key related functions */
|
||||
/* decoding a public key (both rsa and dsa), decoding a signature (rsa and dsa), veryfying them */
|
||||
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
#include <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
Обычный файл
98
libssh/misc.c
Обычный файл
@ -0,0 +1,98 @@
|
||||
/* misc.c */
|
||||
/* some misc routines than aren't really part of the ssh protocols but can be useful to the client */
|
||||
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
#include <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
Обычный файл
382
libssh/options.c
Обычный файл
@ -0,0 +1,382 @@
|
||||
/* options.c */
|
||||
/* handle pre-connection options */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
#include <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
Обычный файл
563
libssh/packet.c
Обычный файл
@ -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
Обычный файл
128
libssh/server.c
Обычный файл
@ -0,0 +1,128 @@
|
||||
/* server.c */
|
||||
|
||||
/* No. It doesn't work yet. It's just hard to have 2 separated trees, one for releases
|
||||
* and one for development */
|
||||
/*
|
||||
Copyright 2004 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
/* from times to times, you need to serve your friends */
|
||||
/* and, perhaps, ssh connections. */
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
#include <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
Обычный файл
124
libssh/session.c
Обычный файл
@ -0,0 +1,124 @@
|
||||
/* session.c */
|
||||
/* contains the non-networking functions ssh_* */
|
||||
/*
|
||||
* Copyright 2005 Aris Adamantiadis
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA. */
|
||||
|
||||
/* ssh_new() returns a newly allocated SSH_SESSION structure pointer */
|
||||
#include <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
Обычный файл
1290
libssh/sftp.c
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
70
libssh/string.c
Обычный файл
70
libssh/string.c
Обычный файл
@ -0,0 +1,70 @@
|
||||
/*string.c */
|
||||
/* string manipulations... */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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
Обычный файл
329
libssh/wrapper.c
Обычный файл
@ -0,0 +1,329 @@
|
||||
/* wrapper.c */
|
||||
/* wrapping functions for crypto functions. */
|
||||
/* why a wrapper ? let's say you want to port libssh from libcrypto of openssl to libfoo */
|
||||
/* you are going to spend hours to remove every references to SHA1_Update() to libfoo_sha1_update */
|
||||
/* after the work is finished, you're going to have only this file to modify */
|
||||
/* it's not needed to say that your modifications are welcome */
|
||||
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include <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
Исполняемый файл
40
mkinstalldirs
Исполняемый файл
@ -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
Обычный файл
434
sample.c
Обычный файл
@ -0,0 +1,434 @@
|
||||
/* client.c */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include <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щs\n");
|
||||
to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT,NULL);
|
||||
for(i=0;i<1000;++i){
|
||||
len=sftp_write(to,data,8000);
|
||||
printf("wrote %d bytes\n",len);
|
||||
if(len != 8000){
|
||||
printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session));
|
||||
}
|
||||
}
|
||||
sftp_file_close(to);
|
||||
/* close the sftp session */
|
||||
sftp_free(sftp);
|
||||
printf("session sftp terminщe\n");
|
||||
}
|
||||
|
||||
int auth_kbdint(SSH_SESSION *session){
|
||||
int err=ssh_userauth_kbdint(session,NULL,NULL);
|
||||
char *name,*instruction,*prompt,*ptr;
|
||||
char buffer[128];
|
||||
int i,n;
|
||||
char echo;
|
||||
while (err==SSH_AUTH_INFO){
|
||||
name=ssh_userauth_kbdint_getname(session);
|
||||
instruction=ssh_userauth_kbdint_getinstruction(session);
|
||||
n=ssh_userauth_kbdint_getnprompts(session);
|
||||
if(strlen(name)>0)
|
||||
printf("%s\n",name);
|
||||
if(strlen(instruction)>0)
|
||||
printf("%s\n",instruction);
|
||||
for(i=0;i<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
Символическая ссылка
1
samplesftp
Символическая ссылка
@ -0,0 +1 @@
|
||||
samplessh
|
Двоичные данные
samplessh
Исполняемый файл
Двоичные данные
samplessh
Исполняемый файл
Двоичный файл не отображается.
Двоичные данные
samplesshd
Исполняемый файл
Двоичные данные
samplesshd
Исполняемый файл
Двоичный файл не отображается.
50
samplesshd.c
Обычный файл
50
samplesshd.c
Обычный файл
@ -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
Обычный файл
202
ssh1/auth1.c
Обычный файл
@ -0,0 +1,202 @@
|
||||
/* auth1.c deals with authentication with SSH-1 protocol */
|
||||
/*
|
||||
Copyright 2005 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include <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
Обычный файл
244
ssh1/channels1.c
Обычный файл
@ -0,0 +1,244 @@
|
||||
/* channels1.c */
|
||||
/* Support for SSH-1 type channels */
|
||||
/*
|
||||
Copyright 2005 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <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 */
|
Загрузка…
Ссылка в новой задаче
Block a user