1
1
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@1 7dcaeef0-15fb-0310-b436-a5af3365683c
Этот коммит содержится в:
Aris Adamantiadis 2005-07-05 01:21:44 +00:00
Коммит c65f56aefa
78 изменённых файлов: 41120 добавлений и 0 удалений

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 поставляемый Исполняемый файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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 поставляемый Исполняемый файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

6195
configure поставляемый Исполняемый файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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 Обычный файл
Просмотреть файл

@ -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>
&nbsp;&nbsp;&nbsp;&nbsp;go_out()...<br>
if(i>=256)<br>
&nbsp;&nbsp;&nbsp;&nbsp;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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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]

Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1962
doc/draft-ietf-secsh-filexfer-03.txt Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

2130
doc/draft-ietf-secsh-filexfer-04.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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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 Символическая ссылка
Просмотреть файл

@ -0,0 +1 @@
../../config.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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Исполняемый файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл

Двоичный файл не отображается.

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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 Обычный файл
Просмотреть файл

@ -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 Исполняемый файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Символическая ссылка
Просмотреть файл

@ -0,0 +1 @@
samplessh

Двоичные данные
samplessh Исполняемый файл

Двоичный файл не отображается.

Двоичные данные
samplesshd Исполняемый файл

Двоичный файл не отображается.

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 */