This commit was generated by cvs2svn to compensate for changes in r76259,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Brian Feldman 2001-05-04 03:57:05 +00:00
commit 3ed16d1511
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76260
118 changed files with 10209 additions and 2893 deletions

View File

@ -1,7 +1,7 @@
This file is part of the ssh software.
This file is part of the OpenSSH software.
The licences which components of this software falls under are as
follows. First, we will summarize and say that that all components
The licences which components of this software fall under are as
follows. First, we will summarize and say that all components
are under a BSD licence, or a licence more free than that.
OpenSSH contains no GPL code.
@ -29,7 +29,7 @@ OpenSSH contains no GPL code.
have been removed from OpenSSH, ie.
- RSA is no longer included, found in the OpenSSL library
- IDEA is no longer included, it's use is depricated
- IDEA is no longer included, its use is deprecated
- DES is now external, in the OpenSSL library
- GMP is no longer used, and instead we call BN code from OpenSSL
- Zlib is now external, in a library

View File

@ -1,8 +1,9 @@
# $OpenBSD: Makefile,v 1.6 2000/08/31 21:52:23 markus Exp $
# $OpenBSD: Makefile,v 1.8 2001/02/04 11:11:53 djm Exp $
.include <bsd.own.mk>
SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server
SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server \
ssh-keyscan sftp
distribution:
install -C -o root -g wheel -m 0644 ${.CURDIR}/ssh_config \

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile.inc,v 1.13 2001/01/29 01:58:14 niklas Exp $
CFLAGS+= -I${.CURDIR}/..
CFLAGS+= -Wall

View File

@ -1,567 +1,25 @@
[ Please note that this file has not been updated for OpenSSH and
covers the ssh-1.2.12 release from Dec 1995 only. ]
Ssh (Secure Shell) is a program to log into another computer over a
network, to execute commands in a remote machine, and to move files
from one machine to another. It provides strong authentication and
secure communications over insecure channels. It is intended as a
replacement for rlogin, rsh, rcp, and rdist.
See the file INSTALL for installation instructions. See COPYING for
license terms and other legal issues. See RFC for a description of
the protocol. There is a WWW page for ssh; see http://www.cs.hut.fi/ssh.
This file has been updated to match ssh-1.2.12.
FEATURES
o Strong authentication. Closes several security holes (e.g., IP,
routing, and DNS spoofing). New authentication methods: .rhosts
together with RSA based host authentication, and pure RSA
authentication.
o Improved privacy. All communications are automatically and
transparently encrypted. RSA is used for key exchange, and a
conventional cipher (normally IDEA, DES, or triple-DES) for
encrypting the session. Encryption is started before
authentication, and no passwords or other information is
transmitted in the clear. Encryption is also used to protect
against spoofed packets.
o Secure X11 sessions. The program automatically sets DISPLAY on
the server machine, and forwards any X11 connections over the
secure channel. Fake Xauthority information is automatically
generated and forwarded to the remote machine; the local client
automatically examines incoming X11 connections and replaces the
fake authorization data with the real data (never telling the
remote machine the real information).
o Arbitrary TCP/IP ports can be redirected through the encrypted channel
in both directions (e.g., for e-cash transactions).
o No retraining needed for normal users; everything happens
automatically, and old .rhosts files will work with strong
authentication if administration installs host key files.
o Never trusts the network. Minimal trust on the remote side of
the connection. Minimal trust on domain name servers. Pure RSA
authentication never trusts anything but the private key.
o Client RSA-authenticates the server machine in the beginning of
every connection to prevent trojan horses (by routing or DNS
spoofing) and man-in-the-middle attacks, and the server
RSA-authenticates the client machine before accepting .rhosts or
/etc/hosts.equiv authentication (to prevent DNS, routing, or
IP-spoofing).
o Host authentication key distribution can be centrally by the
administration, automatically when the first connection is made
to a machine (the key obtained on the first connection will be
recorded and used for authentication in the future), or manually
by each user for his/her own use. The central and per-user host
key repositories are both used and complement each other. Host
keys can be generated centrally or automatically when the software
is installed. Host authentication keys are typically 1024 bits.
o Any user can create any number of user authentication RSA keys for
his/her own use. Each user has a file which lists the RSA public
keys for which proof of possession of the corresponding private
key is accepted as authentication. User authentication keys are
typically 1024 bits.
o The server program has its own server RSA key which is
automatically regenerated every hour. This key is never saved in
any file. Exchanged session keys are encrypted using both the
server key and the server host key. The purpose of the separate
server key is to make it impossible to decipher a captured session by
breaking into the server machine at a later time; one hour from
the connection even the server machine cannot decipher the session
key. The key regeneration interval is configurable. The server
key is normally 768 bits.
o An authentication agent, running in the user's laptop or local
workstation, can be used to hold the user's RSA authentication
keys. Ssh automatically forwards the connection to the
authentication agent over any connections, and there is no need to
store the RSA authentication keys on any machine in the network
(except the user's own local machine). The authentication
protocols never reveal the keys; they can only be used to verify
that the user's agent has a certain key. Eventually the agent
could rely on a smart card to perform all authentication
computations.
o The software can be installed and used (with restricted
functionality) even without root privileges.
o The client is customizable in system-wide and per-user
configuration files. Most aspects of the client's operation can
be configured. Different options can be specified on a per-host basis.
o Automatically executes conventional rsh (after displaying a
warning) if the server machine is not running sshd.
o Optional compression of all data with gzip (including forwarded X11
and TCP/IP port data), which may result in significant speedups on
slow connections.
o Complete replacement for rlogin, rsh, and rcp.
WHY TO USE SECURE SHELL
Currently, almost all communications in computer networks are done
without encryption. As a consequence, anyone who has access to any
machine connected to the network can listen in on any communication.
This is being done by hackers, curious administrators, employers,
criminals, industrial spies, and governments. Some networks leak off
enough electromagnetic radiation that data may be captured even from a
distance.
When you log in, your password goes in the network in plain
text. Thus, any listener can then use your account to do any evil he
likes. Many incidents have been encountered worldwide where crackers
have started programs on workstations without the owners knowledge
just to listen to the network and collect passwords. Programs for
doing this are available on the Internet, or can be built by a
competent programmer in a few hours.
Any information that you type or is printed on your screen can be
monitored, recorded, and analyzed. For example, an intruder who has
penetrated a host connected to a major network can start a program
that listens to all data flowing in the network, and whenever it
encounters a 16-digit string, it checks if it is a valid credit card
number (using the check digit), and saves the number plus any
surrounding text (to catch expiration date and holder) in a file.
When the intruder has collected a few thousand credit card numbers, he
makes smallish mail-order purchases from a few thousand stores around
the world, and disappears when the goods arrive but before anyone
suspects anything.
Businesses have trade secrets, patent applications in preparation,
pricing information, subcontractor information, client data, personnel
data, financial information, etc. Currently, anyone with access to
the network (any machine on the network) can listen to anything that
goes in the network, without any regard to normal access restrictions.
Many companies are not aware that information can so easily be
recovered from the network. They trust that their data is safe
since nobody is supposed to know that there is sensitive information
in the network, or because so much other data is transferred in the
network. This is not a safe policy.
Individual persons also have confidential information, such as
diaries, love letters, health care documents, information about their
personal interests and habits, professional data, job applications,
tax reports, political documents, unpublished manuscripts, etc.
One should also be aware that economical intelligence and industrial
espionage has recently become a major priority of the intelligence
agencies of major governments. President Clinton recently assigned
economical espionage as the primary task of the CIA, and the French
have repeatedly been publicly boasting about their achievements on
this field.
There is also another frightening aspect about the poor security of
communications. Computer storage and analysis capability has
increased so much that it is feasible for governments, major
companies, and criminal organizations to automatically analyze,
identify, classify, and file information about millions of people over
the years. Because most of the work can be automated, the cost of
collecting this information is getting very low.
Government agencies may be able to monitor major communication
systems, telephones, fax, computer networks, etc., and passively
collect huge amounts of information about all people with any
significant position in the society. Most of this information is not
sensitive, and many people would say there is no harm in someone
getting that information. However, the information starts to get
sensitive when someone has enough of it. You may not mind someone
knowing what you bought from the shop one random day, but you might
not like someone knowing every small thing you have bought in the last
ten years.
If the government some day starts to move into a more totalitarian
direction (one should remember that Nazi Germany was created by
democratic elections), there is considerable danger of an ultimate
totalitarian state. With enough information (the automatically
collected records of an individual can be manually analyzed when the
person becomes interesting), one can form a very detailed picture of
the individual's interests, opinions, beliefs, habits, friends,
lovers, weaknesses, etc. This information can be used to 1) locate
any persons who might oppose the new system 2) use deception to
disturb any organizations which might rise against the government 3)
eliminate difficult individuals without anyone understanding what
happened. Additionally, if the government can monitor communications
too effectively, it becomes too easy to locate and eliminate any
persons distributing information contrary to the official truth.
Fighting crime and terrorism are often used as grounds for domestic
surveillance and restricting encryption. These are good goals, but
there is considerable danger that the surveillance data starts to get
used for questionable purposes. I find that it is better to tolerate
a small amount of crime in the society than to let the society become
fully controlled. I am in favor of a fairly strong state, but the
state must never get so strong that people become unable to spread
contra-offical information and unable to overturn the government if it
is bad. The danger is that when you notice that the government is
too powerful, it is too late. Also, the real power may not be where
the official government is.
For these reasons (privacy, protecting trade secrets, and making it
more difficult to create a totalitarian state), I think that strong
cryptography should be integrated to the tools we use every day.
Using it causes no harm (except for those who wish to monitor
everything), but not using it can cause huge problems. If the society
changes in undesirable ways, then it will be to late to start
encrypting.
Encryption has had a "military" or "classified" flavor to it. There
are no longer any grounds for this. The military can and will use its
own encryption; that is no excuse to prevent the civilians from
protecting their privacy and secrets. Information on strong
encryption is available in every major bookstore, scientific library,
and patent office around the world, and strong encryption software is
available in every country on the Internet.
Some people would like to make it illegal to use encryption, or to
force people to use encryption that governments can break. This
approach offers no protection if the government turns bad. Also, the
"bad guys" will be using true strong encryption anyway. Good
encryption techniques are too widely known to make them disappear.
Thus, any "key escrow encryption" or other restrictions will only help
monitor ordinary people and petty criminals. It does not help against
powerful criminals, terrorists, or espionage, because they will know
how to use strong encryption anyway. (One source for internationally
available encryption software is http://www.cs.hut.fi/crypto.)
OVERVIEW OF SECURE SHELL
The software consists of a number of programs.
sshd Server program run on the server machine. This
listens for connections from client machines, and
whenever it receives a connection, it performs
authentication and starts serving the client.
ssh This is the client program used to log into another
machine or to execute commands on the other machine.
"slogin" is another name for this program.
scp Securely copies files from one machine to another.
ssh-keygen Used to create RSA keys (host keys and user
authentication keys).
ssh-agent Authentication agent. This can be used to hold RSA
keys for authentication.
ssh-add Used to register new keys with the agent.
make-ssh-known-hosts
Used to create the /etc/ssh_known_hosts file.
Ssh is the program users normally use. It is started as
ssh host
or
ssh host command
The first form opens a new shell on the remote machine (after
authentication). The latter form executes the command on the remote
machine.
When started, the ssh connects sshd on the server machine, verifies
that the server machine really is the machine it wanted to connect,
exchanges encryption keys (in a manner which prevents an outside
listener from getting the keys), performs authentication using .rhosts
and /etc/hosts.equiv, RSA authentication, or conventional password
based authentication. The server then (normally) allocates a
pseudo-terminal and starts an interactive shell or user program.
The TERM environment variable (describing the type of the user's
terminal) is passed from the client side to the remote side. Also,
terminal modes will be copied from the client side to the remote side
to preserve user preferences (e.g., the erase character).
If the DISPLAY variable is set on the client side, the server will
create a dummy X server and set DISPLAY accordingly. Any connections
to the dummy X server will be forwarded through the secure channel,
and will be made to the real X server from the client side. An
arbitrary number of X programs can be started during the session, and
starting them does not require anything special from the user. (Note
that the user must not manually set DISPLAY, because then it would
connect directly to the real display instead of going through the
encrypted channel). This behavior can be disabled in the
configuration file or by giving the -x option to the client.
Arbitrary IP ports can be forwarded over the secure channel. The
program then creates a port on one side, and whenever a connection is
opened to this port, it will be passed over the secure channel, and a
connection will be made from the other side to a specified host:port
pair. Arbitrary IP forwarding must always be explicitly requested,
and cannot be used to forward privileged ports (unless the user is
root). It is possible to specify automatic forwards in a per-user
configuration file, for example to make electronic cash systems work
securely.
If there is an authentication agent on the client side, connection to
it will be automatically forwarded to the server side.
For more infomation, see the manual pages ssh(1), sshd(8), scp(1),
ssh-keygen(1), ssh-agent(1), ssh-add(1), and make-ssh-known-hosts(1)
included in this distribution.
X11 CONNECTION FORWARDING
X11 forwarding serves two purposes: it is a convenience to the user
because there is no need to set the DISPLAY variable, and it provides
encrypted X11 connections. I cannot think of any other easy way to
make X11 connections encrypted; modifying the X server, clients or
libraries would require special work for each machine, vendor and
application. Widely used IP-level encryption does not seem likely for
several years. Thus what we have left is faking an X server on the
same machine where the clients are run, and forwarding the connections
to a real X server over the secure channel.
X11 forwarding works as follows. The client extracts Xauthority
information for the server. It then creates random authorization
data, and sends the random data to the server. The server allocates
an X11 display number, and stores the (fake) Xauthority data for this
display. Whenever an X11 connection is opened, the server forwards
the connection over the secure channel to the client, and the client
parses the first packet of the X11 protocol, substitutes real
authentication data for the fake data (if the fake data matched), and
forwards the connection to the real X server.
If the display does not have Xauthority data, the server will create a
unix domain socket in /tmp/.X11-unix, and use the unix domain socket
as the display. No authentication information is forwarded in this
case. X11 connections are again forwarded over the secure channel.
To the X server the connections appear to come from the client
machine, and the server must have connections allowed from the local
machine. Using authentication data is always recommended because not
using it makes the display insecure. If XDM is used, it automatically
generates the authentication data.
One should be careful not to use "xin" or "xstart" or other similar
scripts that explicitly set DISPLAY to start X sessions in a remote
machine, because the connection will then not go over the secure
channel. The recommended way to start a shell in a remote machine is
xterm -e ssh host &
and the recommended way to execute an X11 application in a remote
machine is
ssh -n host emacs &
If you need to type a password/passphrase for the remote machine,
ssh -f host emacs
may be useful.
RSA AUTHENTICATION
RSA authentication is based on public key cryptograpy. The idea is
that there are two encryption keys, one for encryption and another for
decryption. It is not possible (on human timescale) to derive the
decryption key from the encryption key. The encryption key is called
the public key, because it can be given to anyone and it is not
secret. The decryption key, on the other hand, is secret, and is
called the private key.
RSA authentication is based on the impossibility of deriving the
private key from the public key. The public key is stored on the
server machine in the user's $HOME/.ssh/authorized_keys file. The
private key is only kept on the user's local machine, laptop, or other
secure storage. Then the user tries to log in, the client tells the
server the public key that the user wishes to use for authentication.
The server then checks if this public key is admissible. If so, it
generates a 256 bit random number, encrypts it with the public key,
and sends the value to the client. The client then decrypts the
number with its private key, computes a 128 bit MD5 checksum from the
resulting data, and sends the checksum back to the server. (Only a
checksum is sent to prevent chosen-plaintext attacks against RSA.)
The server checks computes a checksum from the correct data,
and compares the checksums. Authentication is accepted if the
checksums match. (Theoretically this indicates that the client
only probably knows the correct key, but for all practical purposes
there is no doubt.)
The RSA private key can be protected with a passphrase. The
passphrase can be any string; it is hashed with MD5 to produce an
encryption key for IDEA, which is used to encrypt the private part of
the key file. With passphrase, authorization requires access to the key
file and the passphrase. Without passphrase, authorization only
depends on possession of the key file.
RSA authentication is the most secure form of authentication supported
by this software. It does not rely on the network, routers, domain
name servers, or the client machine. The only thing that matters is
access to the private key.
All this, of course, depends on the security of the RSA algorithm
itself. RSA has been widely known since about 1978, and no effective
methods for breaking it are known if it is used properly. Care has
been taken to avoid the well-known pitfalls. Breaking RSA is widely
believed to be equivalent to factoring, which is a very hard
mathematical problem that has received considerable public research.
So far, no effective methods are known for numbers bigger than about
512 bits. However, as computer speeds and factoring methods are
increasing, 512 bits can no longer be considered secure. The
factoring work is exponential, and 768 or 1024 bits are widely
considered to be secure in the near future.
RHOSTS AUTHENTICATION
Conventional .rhosts and hosts.equiv based authentication mechanisms
are fundamentally insecure due to IP, DNS (domain name server) and
routing spoofing attacks. Additionally this authentication method
relies on the integrity of the client machine. These weaknesses is
tolerable, and been known and exploited for a long time.
Ssh provides an improved version of these types of authentication,
because they are very convenient for the user (and allow easy
transition from rsh and rlogin). It permits these types of
authentication, but additionally requires that the client host be
authenticated using RSA.
The server has a list of host keys stored in /etc/ssh_known_host, and
additionally each user has host keys in $HOME/.ssh/known_hosts. Ssh
uses the name servers to obtain the canonical name of the client host,
looks for its public key in its known host files, and requires the
client to prove that it knows the private host key. This prevents IP
and routing spoofing attacks (as long as the client machine private
host key has not been compromized), but is still vulnerable to DNS
attacks (to a limited extent), and relies on the integrity of the
client machine as to who is requesting to log in. This prevents
outsiders from attacking, but does not protect against very powerful
attackers. If maximal security is desired, only RSA authentication
should be used.
It is possible to enable conventional .rhosts and /etc/hosts.equiv
authentication (without host authentication) at compile time by giving
the option --with-rhosts to configure. However, this is not
recommended, and is not done by default.
These weaknesses are present in rsh and rlogin. No improvement in
security will be obtained unless rlogin and rsh are completely
disabled (commented out in /etc/inetd.conf). This is highly
recommended.
WEAKEST LINKS IN SECURITY
One should understand that while this software may provide
cryptographically secure communications, it may be easy to
monitor the communications at their endpoints.
Basically, anyone with root access on the local machine on which you
are running the software may be able to do anything. Anyone with root
access on the server machine may be able to monitor your
communications, and a very talented root user might even be able to
send his/her own requests to your authentication agent.
One should also be aware that computers send out electromagnetic
radition that can sometimes be picked up hundreds of meters away.
Your keyboard is particularly easy to listen to. The image on your
monitor might also be seen on another monitor in a van parked behind
your house.
Beware that unwanted visitors might come to your home or office and
use your machine while you are away. They might also make
modifications or install bugs in your hardware or software.
Beware that the most effective way for someone to decrypt your data
may be with a rubber hose.
LEGAL ISSUES
As far as I am concerned, anyone is permitted to use this software
freely. However, see the file COPYING for detailed copying,
licensing, and distribution information.
In some countries, particularly France, Russia, Iraq, and Pakistan,
it may be illegal to use any encryption at all without a special
permit, and the rumor has it that you cannot get a permit for any
strong encryption.
This software may be freely imported into the United States; however,
the United States Government may consider re-exporting it a criminal
offence.
Note that any information and cryptographic algorithms used in this
software are publicly available on the Internet and at any major
bookstore, scientific library, or patent office worldwide.
THERE IS NO WARRANTY FOR THIS PROGRAM. Please consult the file
COPYING for more information.
MAILING LISTS AND OTHER INFORMATION
There is a mailing list for ossh. It is ossh@sics.se. If you would
like to join, send a message to majordomo@sics.se with "subscribe
ssh" in body.
The WWW home page for ssh is http://www.cs.hut.fi/ssh. It contains an
archive of the mailing list, and detailed information about new
releases, mailing lists, and other relevant issues.
Bug reports should be sent to ossh-bugs@sics.se.
ABOUT THE AUTHOR
This software was written by Tatu Ylonen <ylo@cs.hut.fi>. I work as a
researcher at Helsinki University of Technology, Finland. For more
information, see http://www.cs.hut.fi/~ylo/. My PGP public key is
available via finger from ylo@cs.hut.fi and from the key servers. I
prefer PGP encrypted mail.
The author can be contacted via ordinary mail at
Tatu Ylonen
Helsinki University of Technology
Otakaari 1
FIN-02150 ESPOO
Finland
Fax. +358-0-4513293
ACKNOWLEDGEMENTS
I thank Tero Kivinen, Timo Rinne, Janne Snabb, and Heikki Suonsivu for
their help and comments in the design, implementation and porting of
this software. I also thank numerous contributors, including but not
limited to Walker Aumann, Jurgen Botz, Hans-Werner Braun, Stephane
Bortzmeyer, Adrian Colley, Michael Cooper, David Dombek, Jerome
Etienne, Bill Fithen, Mark Fullmer, Bert Gijsbers, Andreas Gustafsson,
Michael Henits, Steve Johnson, Thomas Koenig, Felix Leitner, Gunnar
Lindberg, Andrew Macpherson, Marc Martinec, Paul Mauvais, Donald
McKillican, Leon Mlakar, Robert Muchsel, Mark Treacy, Bryan
O'Sullivan, Mikael Suokas, Ollivier Robert, Jakob Schlyter, Tomasz
Surmacz, Alvar Vinacua, Petri Virkkula, Michael Warfield, and
Cristophe Wolfhugel.
Thanks also go to Philip Zimmermann, whose PGP software and the
associated legal battle provided inspiration, motivation, and many
useful techniques, and to Bruce Schneier whose book Applied
Cryptography has done a great service in widely distributing knowledge
about cryptographic methods.
Copyright (c) 1995 Tatu Ylonen, Espoo, Finland.
This release of OpenSSH is for OpenBSD systems only.
Please read
http://www.openssh.com/portable.html
if you want to install OpenSSH on other operating systems.
To extract and install this release on your OpenBSD system use:
# cd /usr/src/usr.bin
# tar xvfz .../openssh-x.y.tgz
# cd ssh
# make obj
# make cleandir
# make depend
# make
# make install
# cp ssh_config sshd_config /etc
OpenSSH is a derivative of the original and free ssh 1.2.12 release
by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels
Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer
features and created OpenSSH. Markus Friedl contributed the support
for SSH protocol versions 1.5 and 2.0.
See http://www.openssh.com/ for more information.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995,1999 Theo de Raadt
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -24,10 +24,10 @@
*/
#include "includes.h"
RCSID("$OpenBSD: atomicio.c,v 1.7 2000/10/18 18:04:02 markus Exp $");
RCSID("$OpenBSD: atomicio.c,v 1.9 2001/03/02 18:54:30 deraadt Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "atomicio.h"
/*
* ensure all of data on socket comes through. f==read || f==write

31
crypto/openssh/atomicio.h Normal file
View File

@ -0,0 +1,31 @@
/* $OpenBSD: atomicio.h,v 1.3 2001/03/02 18:54:30 deraadt Exp $ */
/*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Ensure all of data on socket comes through. f==read || f==write
*/
ssize_t atomicio(ssize_t (*f)(), int fd, void *s, size_t n);

104
crypto/openssh/auth-chall.c Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
#include "auth.h"
#include "log.h"
#ifdef BSD_AUTH
char *
get_challenge(Authctxt *authctxt, char *devs)
{
char *challenge;
if (authctxt->as != NULL) {
debug2("try reuse session");
challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
if (challenge != NULL) {
debug2("reuse bsd auth session");
return challenge;
}
auth_close(authctxt->as);
authctxt->as = NULL;
}
debug2("new bsd auth session");
if (devs == NULL || strlen(devs) == 0)
devs = authctxt->style;
debug3("bsd auth: devs %s", devs ? devs : "<default>");
authctxt->as = auth_userchallenge(authctxt->user, devs, "auth-ssh",
&challenge);
if (authctxt->as == NULL)
return NULL;
debug2("get_challenge: <%s>", challenge ? challenge : "EMPTY");
return challenge;
}
int
verify_response(Authctxt *authctxt, char *response)
{
int authok;
if (authctxt->as == 0)
error("verify_response: no bsd auth session");
authok = auth_userresponse(authctxt->as, response, 0);
authctxt->as = NULL;
debug("verify_response: <%s> = <%d>", response, authok);
return authok != 0;
}
#else
#ifdef SKEY
#include <skey.h>
char *
get_challenge(Authctxt *authctxt, char *devs)
{
static char challenge[1024];
struct skey skey;
if (skeychallenge(&skey, authctxt->user, challenge) == -1)
return NULL;
strlcat(challenge, "\nS/Key Password: ", sizeof challenge);
return challenge;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return (authctxt->valid &&
skey_haskey(authctxt->pw->pw_name) == 0 &&
skey_passcheck(authctxt->pw->pw_name, response) != -1);
}
#else
/* not available */
char *
get_challenge(Authctxt *authctxt, char *devs)
{
return NULL;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return 0;
}
#endif
#endif

View File

@ -2,10 +2,6 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* RSA-based authentication. This code determines whether to admit a login
* based on RSA authentication. This file also contains functions to check
* validity of the host key.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
@ -14,12 +10,16 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-options.c,v 1.5 2000/10/09 21:32:34 markus Exp $");
RCSID("$OpenBSD: auth-options.c,v 1.16 2001/03/18 12:07:52 markus Exp $");
#include "ssh.h"
#include "packet.h"
#include "xmalloc.h"
#include "match.h"
#include "log.h"
#include "canohost.h"
#include "channels.h"
#include "auth-options.h"
#include "servconf.h"
/* Flags set authorized_keys flags */
int no_port_forwarding_flag = 0;
@ -33,6 +33,8 @@ char *forced_command = NULL;
/* "environment=" options. */
struct envstring *custom_environment = NULL;
extern ServerOptions options;
void
auth_clear_options(void)
{
@ -50,105 +52,113 @@ auth_clear_options(void)
xfree(forced_command);
forced_command = NULL;
}
channel_clear_permitted_opens();
}
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */
/*
* return 1 if access is granted, 0 if not.
* side effect: sets key option flags
*/
int
auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
{
const char *cp;
if (!options)
return 1;
int i;
/* reset options */
auth_clear_options();
while (*options && *options != ' ' && *options != '\t') {
if (!opts)
return 1;
while (*opts && *opts != ' ' && *opts != '\t') {
cp = "no-port-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Port forwarding disabled.");
no_port_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-agent-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Agent forwarding disabled.");
no_agent_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-X11-forwarding";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("X11 forwarding disabled.");
no_x11_forwarding_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "no-pty";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Pty allocation disabled.");
no_pty_flag = 1;
options += strlen(cp);
opts += strlen(cp);
goto next_option;
}
cp = "command=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
int i;
options += strlen(cp);
forced_command = xmalloc(strlen(options) + 1);
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
opts += strlen(cp);
forced_command = xmalloc(strlen(opts) + 1);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
forced_command[i++] = '"';
continue;
}
forced_command[i++] = *options++;
forced_command[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
file, linenum);
xfree(forced_command);
forced_command = NULL;
goto bad_option;
}
forced_command[i] = 0;
packet_send_debug("Forced command: %.900s", forced_command);
options++;
opts++;
goto next_option;
}
cp = "environment=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
int i;
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
char *s;
struct envstring *new_envstring;
options += strlen(cp);
s = xmalloc(strlen(options) + 1);
opts += strlen(cp);
s = xmalloc(strlen(opts) + 1);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
s[i++] = '"';
continue;
}
s[i++] = *options++;
s[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
file, linenum);
xfree(s);
goto bad_option;
}
s[i] = 0;
packet_send_debug("Adding to environment: %.900s", s);
debug("Adding to environment: %.900s", s);
options++;
opts++;
new_envstring = xmalloc(sizeof(struct envstring));
new_envstring->s = s;
new_envstring->next = custom_environment;
@ -156,66 +166,125 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
goto next_option;
}
cp = "from=\"";
if (strncmp(options, cp, strlen(cp)) == 0) {
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
int mname, mip;
char *patterns = xmalloc(strlen(options) + 1);
int i;
options += strlen(cp);
const char *remote_ip = get_remote_ipaddr();
const char *remote_host = get_canonical_hostname(
options.reverse_mapping_check);
char *patterns = xmalloc(strlen(opts) + 1);
opts += strlen(cp);
i = 0;
while (*options) {
if (*options == '"')
while (*opts) {
if (*opts == '"')
break;
if (*options == '\\' && options[1] == '"') {
options += 2;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
patterns[i++] = '"';
continue;
}
patterns[i++] = *options++;
patterns[i++] = *opts++;
}
if (!*options) {
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
SSH_USER_PERMITTED_KEYS, linenum);
continue;
file, linenum);
xfree(patterns);
goto bad_option;
}
patterns[i] = 0;
options++;
opts++;
/*
* Deny access if we get a negative
* match for the hostname or the ip
* or if we get not match at all
*/
mname = match_hostname(get_canonical_hostname(),
patterns, strlen(patterns));
mip = match_hostname(get_remote_ipaddr(),
patterns, strlen(patterns));
mname = match_hostname(remote_host, patterns,
strlen(patterns));
mip = match_hostname(remote_ip, patterns,
strlen(patterns));
xfree(patterns);
if (mname == -1 || mip == -1 ||
(mname != 1 && mip != 1)) {
log("Authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
pw->pw_name, get_canonical_hostname(),
get_remote_ipaddr());
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
get_canonical_hostname());
log("Authentication tried for %.100s with "
"correct key but not from a permitted "
"host (host=%.200s, ip=%.200s).",
pw->pw_name, remote_host, remote_ip);
packet_send_debug("Your host '%.200s' is not "
"permitted to use this key for login.",
remote_host);
/* deny access */
return 0;
}
/* Host name matches. */
goto next_option;
}
cp = "permitopen=\"";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
u_short port;
char *c, *ep;
char *patterns = xmalloc(strlen(opts) + 1);
opts += strlen(cp);
i = 0;
while (*opts) {
if (*opts == '"')
break;
if (*opts == '\\' && opts[1] == '"') {
opts += 2;
patterns[i++] = '"';
continue;
}
patterns[i++] = *opts++;
}
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
file, linenum);
packet_send_debug("%.100s, line %lu: missing end quote",
file, linenum);
xfree(patterns);
goto bad_option;
}
patterns[i] = 0;
opts++;
c = strchr(patterns, ':');
if (c == NULL) {
debug("%.100s, line %lu: permitopen: missing colon <%.100s>",
file, linenum, patterns);
packet_send_debug("%.100s, line %lu: missing colon",
file, linenum);
xfree(patterns);
goto bad_option;
}
*c = 0;
c++;
port = strtol(c, &ep, 0);
if (c == ep) {
debug("%.100s, line %lu: permitopen: missing port <%.100s>",
file, linenum, patterns);
packet_send_debug("%.100s, line %lu: missing port",
file, linenum);
xfree(patterns);
goto bad_option;
}
if (options.allow_tcp_forwarding)
channel_add_permitted_opens(patterns, port);
xfree(patterns);
goto next_option;
}
next_option:
/*
* Skip the comma, and move to the next option
* (or break out if there are no more).
*/
if (!*options)
if (!*opts)
fatal("Bugs in auth-options.c option processing.");
if (*options == ' ' || *options == '\t')
if (*opts == ' ' || *opts == '\t')
break; /* End of options. */
if (*options != ',')
if (*opts != ',')
goto bad_option;
options++;
opts++;
/* Process the next option. */
}
/* grant access */
@ -223,9 +292,9 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
bad_option:
log("Bad options in %.100s file, line %lu: %.50s",
SSH_USER_PERMITTED_KEYS, linenum, options);
file, linenum, opts);
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
SSH_USER_PERMITTED_KEYS, linenum, options);
file, linenum, opts);
/* deny access */
return 0;
}

View File

@ -11,10 +11,17 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* $OpenBSD: auth-options.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */
/* $OpenBSD: auth-options.h,v 1.8 2001/01/21 19:05:42 markus Exp $ */
#ifndef AUTH_OPTIONS_H
#define AUTH_OPTIONS_H
/* Linked list of custom environment strings */
struct envstring {
struct envstring *next;
char *s;
};
/* Flags that may be set in authorized_keys options. */
extern int no_port_forwarding_flag;
extern int no_agent_forwarding_flag;
@ -23,8 +30,14 @@ extern int no_pty_flag;
extern char *forced_command;
extern struct envstring *custom_environment;
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */
int auth_parse_options(struct passwd *pw, char *options, unsigned long linenum);
/*
* return 1 if access is granted, 0 if not.
* side effect: sets key option flags
*/
int
auth_parse_options(struct passwd *pw, char *options, char *file,
u_long linenum);
/* reset options flags */
void auth_clear_options(void);

View File

@ -14,13 +14,19 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rhosts.c,v 1.16 2000/10/03 18:03:03 markus Exp $");
RCSID("$OpenBSD: auth-rhosts.c,v 1.23 2001/04/12 19:15:24 markus Exp $");
#include "packet.h"
#include "ssh.h"
#include "xmalloc.h"
#include "uidswap.h"
#include "pathnames.h"
#include "log.h"
#include "servconf.h"
#include "canohost.h"
#include "auth.h"
/* import */
extern ServerOptions options;
/*
* This function processes an rhosts-style file (.rhosts, .shosts, or
@ -147,18 +153,33 @@ check_rhosts_file(const char *filename, const char *hostname,
int
auth_rhosts(struct passwd *pw, const char *client_user)
{
extern ServerOptions options;
char buf[1024];
const char *hostname, *ipaddr;
int ret;
hostname = get_canonical_hostname(options.reverse_mapping_check);
ipaddr = get_remote_ipaddr();
ret = auth_rhosts2(pw, client_user, hostname, ipaddr);
return ret;
}
int
auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
const char *ipaddr)
{
char buf[1024];
struct stat st;
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
unsigned int rhosts_file_index;
u_int rhosts_file_index;
debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s",
client_user, hostname, ipaddr);
/* no user given */
if (pw == NULL)
return 0;
/* Switch to the user's uid. */
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(pw);
/*
* Quick check: if the user has no .shosts or .rhosts files, return
* failure immediately without doing costly lookups from name
@ -177,25 +198,22 @@ auth_rhosts(struct passwd *pw, const char *client_user)
/* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
if (!rhosts_files[rhosts_file_index] &&
stat("/etc/hosts.equiv", &st) < 0 &&
stat(SSH_HOSTS_EQUIV, &st) < 0)
stat(_PATH_RHOSTS_EQUIV, &st) < 0 &&
stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0)
return 0;
hostname = get_canonical_hostname();
ipaddr = get_remote_ipaddr();
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
if (pw->pw_uid != 0) {
if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, client_user,
pw->pw_name)) {
packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
hostname, ipaddr);
return 1;
}
if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
pw->pw_name)) {
packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
hostname, ipaddr, SSH_HOSTS_EQUIV);
hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
return 1;
}
}
@ -220,7 +238,7 @@ auth_rhosts(struct passwd *pw, const char *client_user)
return 0;
}
/* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid);
temporarily_use_uid(pw);
/* Check all .rhosts files (currently .shosts and .rhosts). */
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];

View File

@ -21,30 +21,118 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $OpenBSD: auth.h,v 1.7 2000/10/16 09:38:44 djm Exp $
* $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $
*/
#ifndef AUTH_H
#define AUTH_H
#include <openssl/rsa.h>
#ifdef HAVE_LOGIN_CAP
#include <login_cap.h>
#endif
#ifdef BSD_AUTH
#include <bsd_auth.h>
#endif
typedef struct Authctxt Authctxt;
struct Authctxt {
int success;
int postponed;
int valid;
int attempt;
int failures;
char *user;
char *service;
struct passwd *pw;
char *style;
#ifdef BSD_AUTH
auth_session_t *as;
#endif
};
/*
* Tries to authenticate the user using the .rhosts file. Returns true if
* authentication succeeds. If ignore_rhosts is non-zero, this will not
* consider .rhosts and .shosts (/etc/hosts.equiv will still be used).
*/
int auth_rhosts(struct passwd * pw, const char *client_user);
/* extended interface similar to auth_rhosts() */
int
auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
const char *ipaddr);
/*
* Tries to authenticate the user using the .rhosts file and the host using
* its host key. Returns true if authentication succeeds.
*/
int
auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key);
/*
* Tries to authenticate the user using password. Returns true if
* authentication succeeds.
*/
int auth_password(Authctxt *authctxt, const char *password);
/*
* Performs the RSA authentication dialog with the client. This returns 0 if
* the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_rsa(struct passwd * pw, BIGNUM * client_n);
/*
* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
* over the key. Skips any whitespace at the beginning and at end.
*/
int auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n);
/*
* Performs the RSA authentication challenge-response dialog with the client,
* and returns true (non-zero) if the client gave the correct answer to our
* challenge; returns zero if the client gives a wrong answer.
*/
int auth_rsa_challenge_dialog(RSA *pk);
#ifdef KRB4
#include <krb.h>
/*
* Performs Kerberos v4 mutual authentication with the client. This returns 0
* if the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_krb4(const char *server_user, KTEXT auth, char **client);
int krb4_init(uid_t uid);
void krb4_cleanup_proc(void *ignore);
int auth_krb4_password(struct passwd * pw, const char *password);
#ifdef AFS
#include <kafs.h>
/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */
int auth_kerberos_tgt(struct passwd * pw, const char *string);
int auth_afs_token(struct passwd * pw, const char *token_string);
#endif /* AFS */
#endif /* KRB4 */
void do_authentication(void);
void do_authentication2(void);
void userauth_log(Authctxt *authctxt, int authenticated, char *method);
void userauth_reply(Authctxt *authctxt, int authenticated);
Authctxt *authctxt_new(void);
void auth_log(Authctxt *authctxt, int authenticated, char *method, char *info);
void userauth_finish(Authctxt *authctxt, int authenticated, char *method);
int auth_root_allowed(char *method);
int auth2_skey(Authctxt *authctxt);
int auth2_challenge(Authctxt *authctxt, char *devs);
int allowed_user(struct passwd * pw);
char *get_challenge(Authctxt *authctxt, char *devs);
int verify_response(Authctxt *authctxt, char *response);
struct passwd * auth_get_user(void);
#define AUTH_FAIL_MAX 6

View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: auth2-chall.c,v 1.4 2001/03/28 22:43:31 markus Exp $");
#include "ssh2.h"
#include "auth.h"
#include "packet.h"
#include "xmalloc.h"
#include "dispatch.h"
#include "log.h"
void send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo);
void input_userauth_info_response(int type, int plen, void *ctxt);
/*
* try challenge-reponse, return -1 (= postponed) if we have to
* wait for the response.
*/
int
auth2_challenge(Authctxt *authctxt, char *devs)
{
char *challenge;
if (!authctxt->valid || authctxt->user == NULL)
return 0;
if ((challenge = get_challenge(authctxt, devs)) == NULL)
return 0;
send_userauth_into_request(authctxt, challenge, 0);
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
&input_userauth_info_response);
authctxt->postponed = 1;
return 0;
}
void
send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo)
{
int nprompts = 1;
packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
/* name, instruction and language are unused */
packet_put_cstring("");
packet_put_cstring("");
packet_put_cstring("");
packet_put_int(nprompts);
packet_put_cstring(challenge);
packet_put_char(echo);
packet_send();
packet_write_wait();
}
void
input_userauth_info_response(int type, int plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
int authenticated = 0;
u_int nresp, rlen;
char *response, *method = "challenge-reponse";
if (authctxt == NULL)
fatal("input_userauth_info_response: no authctxt");
authctxt->postponed = 0; /* reset */
nresp = packet_get_int();
if (nresp == 1) {
response = packet_get_string(&rlen);
packet_done();
if (strlen(response) == 0) {
/*
* if we received an empty response, resend challenge
* with echo enabled
*/
char *challenge = get_challenge(authctxt, NULL);
if (challenge != NULL) {
send_userauth_into_request(authctxt,
challenge, 1);
authctxt->postponed = 1;
}
} else if (authctxt->valid) {
authenticated = verify_response(authctxt, response);
memset(response, 'r', rlen);
}
xfree(response);
}
/* unregister callback */
if (!authctxt->postponed)
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
userauth_finish(authctxt, authenticated, method);
}

View File

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: authfd.h,v 1.13 2000/10/09 21:51:00 markus Exp $"); */
/* RCSID("$OpenBSD: authfd.h,v 1.16 2000/12/20 19:37:21 markus Exp $"); */
#ifndef AUTHFD_H
#define AUTHFD_H
@ -51,7 +51,7 @@ typedef struct {
} AuthenticationConnection;
/* Returns the number of the authentication fd, or -1 if there is none. */
int ssh_get_authentication_socket();
int ssh_get_authentication_socket(void);
/*
* This should be called for any descriptor returned by
@ -66,7 +66,7 @@ void ssh_close_authentication_socket(int authfd);
* connection could not be opened. The connection should be closed by the
* caller by calling ssh_close_authentication_connection().
*/
AuthenticationConnection *ssh_get_authentication_connection();
AuthenticationConnection *ssh_get_authentication_connection(void);
/*
* Closes the connection to the authentication agent and frees any associated
@ -74,6 +74,11 @@ AuthenticationConnection *ssh_get_authentication_connection();
*/
void ssh_close_authentication_connection(AuthenticationConnection *auth);
/*
* Returns the number authentication identity held by the agent.
*/
int ssh_get_num_identities(AuthenticationConnection *auth, int version);
/*
* Returns the first authentication identity held by the agent or NULL if
* no identies are available. Caller must free comment and key.
@ -96,16 +101,16 @@ Key *ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int v
int
ssh_decrypt_challenge(AuthenticationConnection *auth,
Key *key, BIGNUM * challenge,
unsigned char session_id[16],
unsigned int response_type,
unsigned char response[16]);
u_char session_id[16],
u_int response_type,
u_char response[16]);
/* Requests the agent to sign data using key */
int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
unsigned char **sigp, int *lenp,
unsigned char *data, int datalen);
u_char **sigp, int *lenp,
u_char *data, int datalen);
/*
* Adds an identity to the authentication server. This call is not meant to

View File

@ -2,7 +2,6 @@
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
@ -11,41 +10,27 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* $OpenBSD: authfile.h,v 1.5 2000/10/16 09:38:44 djm Exp $ */
/* $OpenBSD: authfile.h,v 1.6 2001/03/26 08:07:08 markus Exp $ */
#ifndef AUTHFILE_H
#define AUTHFILE_H
/*
* Saves the authentication (private) key in a file, encrypting it with
* passphrase.
* For RSA keys: The identification of the file (lowest 64 bits of n)
* will precede the key to provide identification of the key without
* needing a passphrase.
*/
int
save_private_key(const char *filename, const char *passphrase,
Key * private_key, const char *comment);
key_save_private(Key *key, const char *filename, const char *passphrase,
const char *comment);
/*
* Loads the public part of the key file (public key and comment). Returns 0
* if an error occurred; zero if the public key was successfully read. The
* comment of the key is returned in comment_return if it is non-NULL; the
* caller must free the value with xfree.
*/
int load_public_key(const char *filename, Key * pub, char **comment_return);
int try_load_public_key(const char *filename, Key * pub, char **comment_return);
Key *
key_load_public(const char *filename, char **commentp);
/*
* Loads the private key from the file. Returns 0 if an error is encountered
* (file does not exist or is not readable, or passphrase is bad). This
* initializes the private key. The comment of the key is returned in
* comment_return if it is non-NULL; the caller must free the value with
* xfree.
*/
int
load_private_key(const char *filename, const char *passphrase,
Key * private_key, char **comment_return);
Key *
key_load_public_type(int type, const char *filename, char **commentp);
Key *
key_load_private(const char *filename, const char *passphrase,
char **commentp);
Key *
key_load_private_type(int type, const char *filename, const char *passphrase,
char **commentp);
#endif

View File

@ -10,12 +10,13 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: bufaux.h,v 1.8 2000/09/07 20:27:50 deraadt Exp $"); */
/* RCSID("$OpenBSD: bufaux.h,v 1.11 2001/01/21 19:05:45 markus Exp $"); */
#ifndef BUFAUX_H
#define BUFAUX_H
#include "buffer.h"
#include <openssl/bn.h>
/*
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
@ -29,10 +30,12 @@ int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
int buffer_get_bignum2(Buffer *buffer, BIGNUM * value);
/* Returns an integer from the buffer (4 bytes, msb first). */
unsigned int buffer_get_int(Buffer * buffer);
u_int buffer_get_int(Buffer * buffer);
u_int64_t buffer_get_int64(Buffer *buffer);
/* Stores an integer in the buffer in 4 bytes, msb first. */
void buffer_put_int(Buffer * buffer, unsigned int value);
void buffer_put_int(Buffer * buffer, u_int value);
void buffer_put_int64(Buffer *buffer, u_int64_t value);
/* Returns a character from the buffer (0 - 255). */
int buffer_get_char(Buffer * buffer);
@ -48,10 +51,10 @@ void buffer_put_char(Buffer * buffer, int value);
* stored there. A null character will be automatically appended to the
* returned string, and is not counted in length.
*/
char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
char *buffer_get_string(Buffer * buffer, u_int *length_ptr);
/* Stores and arbitrary binary string in the buffer. */
void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len);
void buffer_put_string(Buffer * buffer, const void *buf, u_int len);
void buffer_put_cstring(Buffer *buffer, const char *s);
#endif /* BUFAUX_H */

View File

@ -12,11 +12,11 @@
*/
#include "includes.h"
RCSID("$OpenBSD: buffer.c,v 1.8 2000/09/07 20:27:50 deraadt Exp $");
RCSID("$OpenBSD: buffer.c,v 1.13 2001/04/12 19:15:24 markus Exp $");
#include "xmalloc.h"
#include "buffer.h"
#include "ssh.h"
#include "log.h"
/* Initializes the buffer structure. */
@ -53,7 +53,7 @@ buffer_clear(Buffer *buffer)
/* Appends data to the buffer, expanding it if necessary. */
void
buffer_append(Buffer *buffer, const char *data, unsigned int len)
buffer_append(Buffer *buffer, const char *data, u_int len)
{
char *cp;
buffer_append_space(buffer, &cp, len);
@ -67,7 +67,7 @@ buffer_append(Buffer *buffer, const char *data, unsigned int len)
*/
void
buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
buffer_append_space(Buffer *buffer, char **datap, u_int len)
{
/* If the buffer is empty, start using it from the beginning. */
if (buffer->offset == buffer->end) {
@ -100,7 +100,7 @@ buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
/* Returns the number of bytes of data in the buffer. */
unsigned int
u_int
buffer_len(Buffer *buffer)
{
return buffer->end - buffer->offset;
@ -109,10 +109,11 @@ buffer_len(Buffer *buffer)
/* Gets data from the beginning of the buffer. */
void
buffer_get(Buffer *buffer, char *buf, unsigned int len)
buffer_get(Buffer *buffer, char *buf, u_int len)
{
if (len > buffer->end - buffer->offset)
fatal("buffer_get: trying to get more bytes than in buffer");
fatal("buffer_get: trying to get more bytes %d than in buffer %d",
len, buffer->end - buffer->offset);
memcpy(buf, buffer->buf + buffer->offset, len);
buffer->offset += len;
}
@ -120,7 +121,7 @@ buffer_get(Buffer *buffer, char *buf, unsigned int len)
/* Consumes the given number of bytes from the beginning of the buffer. */
void
buffer_consume(Buffer *buffer, unsigned int bytes)
buffer_consume(Buffer *buffer, u_int bytes)
{
if (bytes > buffer->end - buffer->offset)
fatal("buffer_consume: trying to get more bytes than in buffer");
@ -130,7 +131,7 @@ buffer_consume(Buffer *buffer, unsigned int bytes)
/* Consumes the given number of bytes from the end of the buffer. */
void
buffer_consume_end(Buffer *buffer, unsigned int bytes)
buffer_consume_end(Buffer *buffer, u_int bytes)
{
if (bytes > buffer->end - buffer->offset)
fatal("buffer_consume_end: trying to get more bytes than in buffer");
@ -151,9 +152,14 @@ void
buffer_dump(Buffer *buffer)
{
int i;
unsigned char *ucp = (unsigned char *) buffer->buf;
u_char *ucp = (u_char *) buffer->buf;
for (i = buffer->offset; i < buffer->end; i++)
fprintf(stderr, " %02x", ucp[i]);
fprintf(stderr, "\n");
for (i = buffer->offset; i < buffer->end; i++) {
fprintf(stderr, "%02x", ucp[i]);
if ((i-buffer->offset)%16==15)
fprintf(stderr, "\r\n");
else if ((i-buffer->offset)%2==1)
fprintf(stderr, " ");
}
fprintf(stderr, "\r\n");
}

View File

@ -11,16 +11,16 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: buffer.h,v 1.6 2000/09/07 20:27:50 deraadt Exp $"); */
/* RCSID("$OpenBSD: buffer.h,v 1.7 2000/12/19 23:17:55 markus Exp $"); */
#ifndef BUFFER_H
#define BUFFER_H
typedef struct {
char *buf; /* Buffer for data. */
unsigned int alloc; /* Number of bytes allocated for data. */
unsigned int offset; /* Offset of first byte containing data. */
unsigned int end; /* Offset of last byte containing data. */
u_int alloc; /* Number of bytes allocated for data. */
u_int offset; /* Offset of first byte containing data. */
u_int end; /* Offset of last byte containing data. */
} Buffer;
/* Initializes the buffer structure. */
void buffer_init(Buffer * buffer);
@ -33,26 +33,26 @@ void buffer_free(Buffer * buffer);
void buffer_clear(Buffer * buffer);
/* Appends data to the buffer, expanding it if necessary. */
void buffer_append(Buffer * buffer, const char *data, unsigned int len);
void buffer_append(Buffer * buffer, const char *data, u_int len);
/*
* Appends space to the buffer, expanding the buffer if necessary. This does
* not actually copy the data into the buffer, but instead returns a pointer
* to the allocated region.
*/
void buffer_append_space(Buffer * buffer, char **datap, unsigned int len);
void buffer_append_space(Buffer * buffer, char **datap, u_int len);
/* Returns the number of bytes of data in the buffer. */
unsigned int buffer_len(Buffer * buffer);
u_int buffer_len(Buffer * buffer);
/* Gets data from the beginning of the buffer. */
void buffer_get(Buffer * buffer, char *buf, unsigned int len);
void buffer_get(Buffer * buffer, char *buf, u_int len);
/* Consumes the given number of bytes from the beginning of the buffer. */
void buffer_consume(Buffer * buffer, unsigned int bytes);
void buffer_consume(Buffer * buffer, u_int bytes);
/* Consumes the given number of bytes from the end of the buffer. */
void buffer_consume_end(Buffer * buffer, unsigned int bytes);
void buffer_consume_end(Buffer * buffer, u_int bytes);
/* Returns a pointer to the first used byte in the buffer. */
char *buffer_ptr(Buffer * buffer);

38
crypto/openssh/canohost.h Normal file
View File

@ -0,0 +1,38 @@
/* $OpenBSD: canohost.h,v 1.6 2001/04/12 19:15:24 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Return the canonical name of the host in the other side of the current
* connection (as returned by packet_get_connection). The host name is
* cached, so it is efficient to call this several times.
*/
const char *get_canonical_hostname(int reverse_mapping_check);
/*
* Returns the IP-address of the remote host as a string. The returned
* string is cached and must not be freed.
*/
const char *get_remote_ipaddr(void);
const char *get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check);
/* Returns the ipaddr/port number of the peer of the socket. */
char * get_peer_ipaddr(int socket);
int get_peer_port(int sock);
char * get_local_ipaddr(int socket);
char * get_local_name(int socket);
/* Returns the port number of the remote/local host. */
int get_remote_port(void);
int get_local_port(void);

View File

@ -1,8 +1,36 @@
/* $OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 deraadt Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: cli.c,v 1.2 2000/10/16 09:38:44 djm Exp $");
RCSID("$OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 deraadt Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "log.h"
#include "cli.h"
#include <vis.h>
static int cli_input = -1;
@ -32,7 +60,7 @@ cli_open(int from_stdin)
cli_input = STDIN_FILENO;
cli_output = STDERR_FILENO;
} else {
cli_input = cli_output = open("/dev/tty", O_RDWR);
cli_input = cli_output = open(_PATH_TTY, O_RDWR);
if (cli_input < 0)
fatal("You have no controlling tty. Cannot read passphrase.");
}
@ -43,7 +71,7 @@ cli_open(int from_stdin)
}
static void
cli_close()
cli_close(void)
{
if (!cli_from_stdin && cli_input >= 0)
close(cli_input);
@ -54,13 +82,13 @@ cli_close()
}
void
intrcatch()
intrcatch(int sig)
{
intr = 1;
}
static void
cli_echo_disable()
cli_echo_disable(void)
{
sigemptyset(&nset);
sigaddset(&nset, SIGTSTP);
@ -83,7 +111,7 @@ cli_echo_disable()
}
static void
cli_echo_restore()
cli_echo_restore(void)
{
if (echo_modified != 0) {
tcsetattr(cli_input, TCSANOW, &otio);
@ -108,12 +136,16 @@ cli_read(char* buf, int size, int echo)
{
char ch = 0;
int i = 0;
int n;
if (!echo)
cli_echo_disable();
while (ch != '\n') {
if (read(cli_input, &ch, 1) != 1)
n = read(cli_input, &ch, 1);
if (n == -1 && (errno == EAGAIN || errno == EINTR))
continue;
if (n != 1)
break;
if (ch == '\n' || intr != 0)
break;
@ -137,18 +169,21 @@ cli_write(char* buf, int size)
output = xmalloc(4*size);
for (p = output, i = 0; i < size; i++) {
if (buf[i] == '\n')
*p++ = buf[i];
else
p = vis(p, buf[i], 0, 0);
}
if (buf[i] == '\n' || buf[i] == '\r')
*p++ = buf[i];
else
p = vis(p, buf[i], 0, 0);
}
len = p - output;
for (pos = 0; pos < len; pos += ret) {
ret = write(cli_output, output + pos, len - pos);
if (ret == -1)
if (ret == -1) {
xfree(output);
return -1;
}
}
xfree(output);
return 0;
}

View File

@ -1,4 +1,30 @@
/* $OpenBSD: cli.h,v 1.2 2000/10/16 09:38:44 djm Exp $ */
/* $OpenBSD: cli.h,v 1.4 2001/03/01 03:38:33 deraadt Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* $OpenBSD: cli.h,v 1.4 2001/03/01 03:38:33 deraadt Exp $ */
#ifndef CLI_H
#define CLI_H
@ -9,8 +35,8 @@
* of response depending on arg. Tries to ensure that no other userland
* buffer is storing the response.
*/
char* cli_read_passphrase(char* prompt, int from_stdin, int echo_enable);
char* cli_prompt(char* prompt, int echo_enable);
void cli_mesg(char* mesg);
char * cli_read_passphrase(char * prompt, int from_stdin, int echo_enable);
char * cli_prompt(char * prompt, int echo_enable);
void cli_mesg(char * mesg);
#endif /* CLI_H */

View File

@ -59,22 +59,28 @@
*/
#include "includes.h"
RCSID("$OpenBSD: clientloop.c,v 1.39 2000/10/27 07:48:22 markus Exp $");
RCSID("$OpenBSD: clientloop.c,v 1.65 2001/04/20 07:17:51 djm Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "ssh1.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "packet.h"
#include "buffer.h"
#include "readconf.h"
#include "ssh2.h"
#include "compat.h"
#include "channels.h"
#include "dispatch.h"
#include "buffer.h"
#include "bufaux.h"
#include "key.h"
#include "kex.h"
#include "log.h"
#include "readconf.h"
#include "clientloop.h"
#include "authfd.h"
#include "atomicio.h"
#include "sshtty.h"
#include "misc.h"
/* import options */
extern Options options;
@ -97,15 +103,6 @@ extern char *host;
*/
static volatile int received_window_change_signal = 0;
/* Terminal modes, as saved by enter_raw_mode. */
static struct termios saved_tio;
/*
* Flag indicating whether we are in raw mode. This is used by
* enter_raw_mode and leave_raw_mode.
*/
static int in_raw_mode = 0;
/* Flag indicating whether the user\'s terminal is in non-blocking mode. */
static int in_non_blocking_mode = 0;
@ -119,60 +116,23 @@ static int stdin_eof; /* EOF has been encountered on standard error. */
static Buffer stdin_buffer; /* Buffer for stdin data. */
static Buffer stdout_buffer; /* Buffer for stdout data. */
static Buffer stderr_buffer; /* Buffer for stderr data. */
static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
static unsigned int buffer_high;/* Soft max buffer size. */
static int max_fd; /* Maximum file descriptor number in select(). */
static u_long stdin_bytes, stdout_bytes, stderr_bytes;
static u_int buffer_high;/* Soft max buffer size. */
static int connection_in; /* Connection to server (input). */
static int connection_out; /* Connection to server (output). */
static int need_rekeying; /* Set to non-zero if rekeying is requested. */
static int session_closed = 0; /* In SSH2: login session closed. */
void client_init_dispatch(void);
int session_ident = -1;
/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
void
leave_raw_mode()
{
if (!in_raw_mode)
return;
in_raw_mode = 0;
if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0)
perror("tcsetattr");
fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL);
}
/* Puts the user\'s terminal in raw mode. */
void
enter_raw_mode()
{
struct termios tio;
if (tcgetattr(fileno(stdin), &tio) < 0)
perror("tcgetattr");
saved_tio = tio;
tio.c_iflag |= IGNPAR;
tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
#ifdef IEXTEN
tio.c_lflag &= ~IEXTEN;
#endif /* IEXTEN */
tio.c_oflag &= ~OPOST;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0)
perror("tcsetattr");
in_raw_mode = 1;
fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL);
}
/*XXX*/
extern Kex *xxx_kex;
/* Restores stdin to blocking mode. */
void
leave_non_blocking()
leave_non_blocking(void)
{
if (in_non_blocking_mode) {
(void) fcntl(fileno(stdin), F_SETFL, 0);
@ -184,7 +144,7 @@ leave_non_blocking()
/* Puts stdin terminal in non-blocking mode. */
void
enter_non_blocking()
enter_non_blocking(void)
{
in_non_blocking_mode = 1;
(void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
@ -211,7 +171,7 @@ window_change_handler(int sig)
void
signal_handler(int sig)
{
if (in_raw_mode)
if (in_raw_mode())
leave_raw_mode();
if (in_non_blocking_mode)
leave_non_blocking();
@ -226,7 +186,7 @@ signal_handler(int sig)
*/
double
get_current_time()
get_current_time(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
@ -240,7 +200,7 @@ get_current_time()
*/
void
client_check_initial_eof_on_stdin()
client_check_initial_eof_on_stdin(void)
{
int len;
char buf[1];
@ -276,12 +236,10 @@ client_check_initial_eof_on_stdin()
* and also process it as an escape character if
* appropriate.
*/
if ((unsigned char) buf[0] == escape_char)
if ((u_char) buf[0] == escape_char)
escape_pending = 1;
else {
else
buffer_append(&stdin_buffer, buf, 1);
stdin_bytes += 1;
}
}
leave_non_blocking();
}
@ -294,9 +252,9 @@ client_check_initial_eof_on_stdin()
*/
void
client_make_packets_from_stdin_data()
client_make_packets_from_stdin_data(void)
{
unsigned int len;
u_int len;
/* Send buffered stdin data to the server. */
while (buffer_len(&stdin_buffer) > 0 &&
@ -309,6 +267,7 @@ client_make_packets_from_stdin_data()
packet_put_string(buffer_ptr(&stdin_buffer), len);
packet_send();
buffer_consume(&stdin_buffer, len);
stdin_bytes += len;
/* If we have a pending EOF, send it now. */
if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
packet_start(SSH_CMSG_EOF);
@ -325,7 +284,7 @@ client_make_packets_from_stdin_data()
*/
void
client_check_window_change()
client_check_window_change(void)
{
struct winsize ws;
@ -362,45 +321,37 @@ client_check_window_change()
*/
void
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
int *maxfdp, int rekeying)
{
/* Initialize select masks. */
FD_ZERO(readset);
FD_ZERO(writeset);
/* Add any selections by the channel mechanism. */
channel_prepare_select(readsetp, writesetp, maxfdp, rekeying);
if (!compat20) {
/* Read from the connection, unless our buffers are full. */
if (buffer_len(&stdout_buffer) < buffer_high &&
buffer_len(&stderr_buffer) < buffer_high &&
channel_not_very_much_buffered_data())
FD_SET(connection_in, readset);
FD_SET(connection_in, *readsetp);
/*
* Read from stdin, unless we have seen EOF or have very much
* buffered data to send to the server.
*/
if (!stdin_eof && packet_not_very_much_data_to_write())
FD_SET(fileno(stdin), readset);
FD_SET(fileno(stdin), *readsetp);
/* Select stdout/stderr if have data in buffer. */
if (buffer_len(&stdout_buffer) > 0)
FD_SET(fileno(stdout), writeset);
FD_SET(fileno(stdout), *writesetp);
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), writeset);
FD_SET(fileno(stderr), *writesetp);
} else {
FD_SET(connection_in, readset);
FD_SET(connection_in, *readsetp);
}
/* Add any selections by the channel mechanism. */
channel_prepare_select(readset, writeset);
/* Select server connection if have data to write to the server. */
if (packet_have_data_to_write())
FD_SET(connection_out, writeset);
/* move UP XXX */
/* Update maximum file descriptor number, if appropriate. */
if (channel_max_fd() > max_fd)
max_fd = channel_max_fd();
FD_SET(connection_out, *writesetp);
/*
* Wait for something to happen. This will suspend the process until
@ -411,17 +362,22 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
* SSH_MSG_IGNORE packet when the timeout expires.
*/
if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
char buf[100];
/* Some systems fail to clear these automatically. */
FD_ZERO(readset);
FD_ZERO(writeset);
/*
* We have to clear the select masks, because we return.
* We have to return, because the mainloop checks for the flags
* set by the signal handlers.
*/
memset(*readsetp, 0, *maxfdp);
memset(*writesetp, 0, *maxfdp);
if (errno == EINTR)
return;
/* Note: we might still have data in the buffers. */
snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
}
}
@ -487,7 +443,6 @@ client_process_net_input(fd_set * readset)
snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
host);
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
return;
}
@ -495,7 +450,7 @@ client_process_net_input(fd_set * readset)
* There is a kernel bug on Solaris that causes select to
* sometimes wake up even though there is no data available.
*/
if (len < 0 && errno == EAGAIN)
if (len < 0 && (errno == EAGAIN || errno == EINTR))
len = 0;
if (len < 0) {
@ -503,7 +458,6 @@ client_process_net_input(fd_set * readset)
snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
host, strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
return;
}
@ -518,8 +472,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
char string[1024];
pid_t pid;
int bytes = 0;
unsigned int i;
unsigned char ch;
u_int i;
u_char ch;
char *s;
for (i = 0; i < len; i++) {
@ -537,7 +491,6 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
/* Terminate the connection. */
snprintf(string, sizeof string, "%c.\r\n", escape_char);
buffer_append(berr, string, strlen(string));
/*stderr_bytes += strlen(string); XXX*/
quit_pending = 1;
return -1;
@ -547,7 +500,6 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
/* Print a message to that effect to the user. */
snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
buffer_append(berr, string, strlen(string));
/*stderr_bytes += strlen(string); XXX*/
/* Restore terminal modes and suspend. */
client_suspend_self(bin, bout, berr);
@ -555,6 +507,15 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
/* We have been continued. */
continue;
case 'R':
if (compat20) {
if (datafellows & SSH_BUG_NOREKEY)
log("Server does not support re-keying");
else
need_rekeying = 1;
}
continue;
case '&':
/* XXX does not work yet with proto 2 */
if (compat20)
@ -605,6 +566,7 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
"%c?\r\n\
Supported escape sequences:\r\n\
~. - terminate connection\r\n\
~R - Request rekey (SSH protocol 2 only)\r\n\
~^Z - suspend ssh\r\n\
~# - list forwarded connections\r\n\
~& - background ssh (when waiting for connections to terminate)\r\n\
@ -657,7 +619,6 @@ Supported escape sequences:\r\n\
void
client_process_input(fd_set * readset)
{
int ret;
int len;
char buf[8192];
@ -665,6 +626,8 @@ client_process_input(fd_set * readset)
if (FD_ISSET(fileno(stdin), readset)) {
/* Read as much as possible. */
len = read(fileno(stdin), buf, sizeof(buf));
if (len < 0 && (errno == EAGAIN || errno == EINTR))
return; /* we'll try again later */
if (len <= 0) {
/*
* Received EOF or error. They are treated
@ -674,7 +637,6 @@ client_process_input(fd_set * readset)
if (len < 0) {
snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
}
/* Mark that we have seen EOF. */
stdin_eof = 1;
@ -695,16 +657,14 @@ client_process_input(fd_set * readset)
* Just append the data to buffer.
*/
buffer_append(&stdin_buffer, buf, len);
stdin_bytes += len;
} else {
/*
* Normal, successful read. But we have an escape character
* and have to process the characters one by one.
*/
ret = process_escapes(&stdin_buffer, &stdout_buffer, &stderr_buffer, buf, len);
if (ret == -1)
if (process_escapes(&stdin_buffer, &stdout_buffer,
&stderr_buffer, buf, len) == -1)
return;
stdout_bytes += ret;
}
}
}
@ -721,7 +681,7 @@ client_process_output(fd_set * writeset)
len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
buffer_len(&stdout_buffer));
if (len <= 0) {
if (errno == EAGAIN)
if (errno == EINTR || errno == EAGAIN)
len = 0;
else {
/*
@ -730,13 +690,13 @@ client_process_output(fd_set * writeset)
*/
snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
quit_pending = 1;
return;
}
}
/* Consume printed data from the buffer. */
buffer_consume(&stdout_buffer, len);
stdout_bytes += len;
}
/* Write buffered output to stderr. */
if (FD_ISSET(fileno(stderr), writeset)) {
@ -744,7 +704,7 @@ client_process_output(fd_set * writeset)
len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
buffer_len(&stderr_buffer));
if (len <= 0) {
if (errno == EAGAIN)
if (errno == EINTR || errno == EAGAIN)
len = 0;
else {
/* EOF or error, but can't even print error message. */
@ -754,6 +714,7 @@ client_process_output(fd_set * writeset)
}
/* Consume printed characters from the buffer. */
buffer_consume(&stderr_buffer, len);
stderr_bytes += len;
}
}
@ -770,9 +731,9 @@ client_process_output(fd_set * writeset)
*/
void
client_process_buffered_input_packets()
client_process_buffered_input_packets(void)
{
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, NULL);
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);
}
/* scan buf[] for '~' before sending data to the peer */
@ -784,6 +745,17 @@ simple_escape_filter(Channel *c, char *buf, int len)
return process_escapes(&c->input, &c->output, &c->extended, buf, len);
}
void
client_channel_closed(int id, void *arg)
{
if (id != session_ident)
error("client_channel_closed: id %d != session_ident %d",
id, session_ident);
session_closed = 1;
if (in_raw_mode())
leave_raw_mode();
}
/*
* Implements the interactive session with the server. This is called after
* the user has been authenticated, and a command has been started on the
@ -794,8 +766,9 @@ simple_escape_filter(Channel *c, char *buf, int len)
int
client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
{
fd_set *readset = NULL, *writeset = NULL;
double start_time, total_time;
int len;
int max_fd = 0, len, rekeying = 0;
char buf[100];
debug("Entering interactive session.");
@ -810,9 +783,20 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
buffer_high = 64 * 1024;
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
max_fd = connection_in;
if (connection_out > max_fd)
max_fd = connection_out;
max_fd = MAX(connection_in, connection_out);
if (!compat20) {
/* enable nonblocking unless tty */
if (!isatty(fileno(stdin)))
set_nonblock(fileno(stdin));
if (!isatty(fileno(stdout)))
set_nonblock(fileno(stdout));
if (!isatty(fileno(stderr)))
set_nonblock(fileno(stderr));
max_fd = MAX(max_fd, fileno(stdin));
max_fd = MAX(max_fd, fileno(stdout));
max_fd = MAX(max_fd, fileno(stderr));
}
stdin_bytes = 0;
stdout_bytes = 0;
stderr_bytes = 0;
@ -837,80 +821,102 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (have_pty)
enter_raw_mode();
/* Check if we should immediately send eof on stdin. */
if (!compat20)
if (compat20) {
session_ident = ssh2_chan_id;
if (escape_char != -1)
channel_register_filter(session_ident,
simple_escape_filter);
if (session_ident != -1)
channel_register_cleanup(session_ident,
client_channel_closed);
} else {
/* Check if we should immediately send eof on stdin. */
client_check_initial_eof_on_stdin();
if (compat20 && escape_char != -1)
channel_register_filter(ssh2_chan_id, simple_escape_filter);
}
/* Main loop of the client for the interactive session mode. */
while (!quit_pending) {
fd_set readset, writeset;
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets();
if (compat20 && !channel_still_open()) {
debug2("!channel_still_open.");
if (compat20 && session_closed && !channel_still_open())
break;
rekeying = (xxx_kex != NULL && !xxx_kex->done);
if (rekeying) {
debug("rekeying in progress");
} else {
/*
* Make packets of buffered stdin data, and buffer
* them for sending to the server.
*/
if (!compat20)
client_make_packets_from_stdin_data();
/*
* Make packets from buffered channel data, and
* enqueue them for sending to the server.
*/
if (packet_not_very_much_data_to_write())
channel_output_poll();
/*
* Check if the window size has changed, and buffer a
* message about it to the server if so.
*/
client_check_window_change();
if (quit_pending)
break;
}
/*
* Make packets of buffered stdin data, and buffer them for
* sending to the server.
*/
if (!compat20)
client_make_packets_from_stdin_data();
/*
* Make packets from buffered channel data, and buffer them
* for sending to the server.
*/
if (packet_not_very_much_data_to_write())
channel_output_poll();
/*
* Check if the window size has changed, and buffer a message
* about it to the server if so.
*/
client_check_window_change();
if (quit_pending)
break;
/*
* Wait until we have something to do (something becomes
* available on one of the descriptors).
*/
client_wait_until_can_do_something(&readset, &writeset);
client_wait_until_can_do_something(&readset, &writeset,
&max_fd, rekeying);
if (quit_pending)
break;
/* Do channel operations. */
channel_after_select(&readset, &writeset);
/* Do channel operations unless rekeying in progress. */
if (!rekeying) {
channel_after_select(readset, writeset);
if (need_rekeying) {
debug("user requests rekeying");
xxx_kex->done = 0;
kex_send_kexinit(xxx_kex);
need_rekeying = 0;
}
}
/* Buffer input from the connection. */
client_process_net_input(&readset);
client_process_net_input(readset);
if (quit_pending)
break;
if (!compat20) {
/* Buffer data from stdin */
client_process_input(&readset);
client_process_input(readset);
/*
* Process output to stdout and stderr. Output to
* the connection is processed elsewhere (above).
*/
client_process_output(&writeset);
client_process_output(writeset);
}
/* Send as much buffered packet data as possible to the sender. */
if (FD_ISSET(connection_out, &writeset))
if (FD_ISSET(connection_out, writeset))
packet_write_poll();
}
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
/* Terminate the session. */
@ -928,7 +934,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
buffer_append(&stderr_buffer, buf, strlen(buf));
stderr_bytes += strlen(buf);
}
/* Output any buffered data for stdout. */
while (buffer_len(&stdout_buffer) > 0) {
@ -939,6 +944,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
break;
}
buffer_consume(&stdout_buffer, len);
stdout_bytes += len;
}
/* Output any buffered data for stderr. */
@ -950,6 +956,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
break;
}
buffer_consume(&stderr_buffer, len);
stderr_bytes += len;
}
if (have_pty)
@ -980,22 +987,20 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
void
client_input_stdout_data(int type, int plen, void *ctxt)
{
unsigned int data_len;
u_int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
buffer_append(&stdout_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
}
void
client_input_stderr_data(int type, int plen, void *ctxt)
{
unsigned int data_len;
u_int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
buffer_append(&stderr_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
}
@ -1016,14 +1021,102 @@ client_input_exit_status(int type, int plen, void *ctxt)
quit_pending = 1;
}
Channel *
client_request_forwarded_tcpip(const char *request_type, int rchan)
{
Channel* c = NULL;
char *listen_address, *originator_address;
int listen_port, originator_port;
int sock, newch;
/* Get rest of the packet */
listen_address = packet_get_string(NULL);
listen_port = packet_get_int();
originator_address = packet_get_string(NULL);
originator_port = packet_get_int();
packet_done();
debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d",
listen_address, listen_port, originator_address, originator_port);
sock = channel_connect_by_listen_adress(listen_port);
if (sock >= 0) {
newch = channel_new("forwarded-tcpip",
SSH_CHANNEL_CONNECTING, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
xstrdup(originator_address), 1);
c = channel_lookup(newch);
}
xfree(originator_address);
xfree(listen_address);
return c;
}
Channel*
client_request_x11(const char *request_type, int rchan)
{
Channel *c = NULL;
char *originator;
int originator_port;
int sock, newch;
if (!options.forward_x11) {
error("Warning: ssh server tried X11 forwarding.");
error("Warning: this is probably a break in attempt by a malicious server.");
return NULL;
}
originator = packet_get_string(NULL);
if (datafellows & SSH_BUG_X11FWD) {
debug2("buggy server: x11 request w/o originator_port");
originator_port = 0;
} else {
originator_port = packet_get_int();
}
packet_done();
/* XXX check permission */
debug("client_request_x11: request from %s %d", originator,
originator_port);
sock = x11_connect_display();
if (sock >= 0) {
newch = channel_new("x11",
SSH_CHANNEL_X11_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0,
xstrdup("x11"), 1);
c = channel_lookup(newch);
}
xfree(originator);
return c;
}
Channel*
client_request_agent(const char *request_type, int rchan)
{
Channel *c = NULL;
int sock, newch;
if (!options.forward_agent) {
error("Warning: ssh server tried agent forwarding.");
error("Warning: this is probably a break in attempt by a malicious server.");
return NULL;
}
sock = ssh_get_authentication_socket();
if (sock >= 0) {
newch = channel_new("authentication agent connection",
SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
xstrdup("authentication agent connection"), 1);
c = channel_lookup(newch);
}
return c;
}
/* XXXX move to generic input handler */
void
client_input_channel_open(int type, int plen, void *ctxt)
{
Channel *c = NULL;
char *ctype;
int id;
unsigned int len;
u_int len;
int rchan;
int rmaxpack;
int rwindow;
@ -1036,28 +1129,12 @@ client_input_channel_open(int type, int plen, void *ctxt)
debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "x11") == 0 && options.forward_x11) {
int sock;
char *originator;
int originator_port;
originator = packet_get_string(NULL);
if (datafellows & SSH_BUG_X11FWD) {
debug2("buggy server: x11 request w/o originator_port");
originator_port = 0;
} else {
originator_port = packet_get_int();
}
packet_done();
/* XXX check permission */
xfree(originator);
/* XXX move to channels.c */
sock = x11_connect_display();
if (sock >= 0) {
id = channel_new("x11", SSH_CHANNEL_X11_OPEN,
sock, sock, -1, CHAN_X11_WINDOW_DEFAULT,
CHAN_X11_PACKET_DEFAULT, 0, xstrdup("x11"), 1);
c = channel_lookup(id);
}
if (strcmp(ctype, "forwarded-tcpip") == 0) {
c = client_request_forwarded_tcpip(ctype, rchan);
} else if (strcmp(ctype, "x11") == 0) {
c = client_request_x11(ctype, rchan);
} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
c = client_request_agent(ctype, rchan);
}
/* XXX duplicate : */
if (c != NULL) {
@ -1083,9 +1160,45 @@ client_input_channel_open(int type, int plen, void *ctxt)
}
xfree(ctype);
}
void
client_input_channel_req(int type, int plen, void *ctxt)
{
Channel *c = NULL;
int id, reply, success = 0;
char *rtype;
id = packet_get_int();
rtype = packet_get_string(NULL);
reply = packet_get_char();
debug("client_input_channel_req: channel %d rtype %s reply %d",
id, rtype, reply);
if (session_ident == -1) {
error("client_input_channel_req: no channel %d", session_ident);
} else if (id != session_ident) {
error("client_input_channel_req: channel %d: wrong channel: %d",
session_ident, id);
}
c = channel_lookup(id);
if (c == NULL) {
error("client_input_channel_req: channel %d: unknown channel", id);
} else if (strcmp(rtype, "exit-status") == 0) {
success = 1;
exit_status = packet_get_int();
packet_done();
}
if (reply) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
packet_send();
}
xfree(rtype);
}
void
client_init_dispatch_20()
client_init_dispatch_20(void)
{
dispatch_init(&dispatch_protocol_error);
dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
@ -1095,11 +1208,14 @@ client_init_dispatch_20()
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
void
client_init_dispatch_13()
client_init_dispatch_13(void)
{
dispatch_init(NULL);
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
@ -1118,14 +1234,14 @@ client_init_dispatch_13()
&x11_input_open : &deny_input_open);
}
void
client_init_dispatch_15()
client_init_dispatch_15(void)
{
client_init_dispatch_13();
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
}
void
client_init_dispatch()
client_init_dispatch(void)
{
if (compat20)
client_init_dispatch_20();
@ -1134,49 +1250,3 @@ client_init_dispatch()
else
client_init_dispatch_15();
}
void
client_input_channel_req(int id, void *arg)
{
Channel *c = NULL;
unsigned int len;
int success = 0;
int reply;
char *rtype;
rtype = packet_get_string(&len);
reply = packet_get_char();
debug("client_input_channel_req: rtype %s reply %d", rtype, reply);
c = channel_lookup(id);
if (c == NULL)
fatal("client_input_channel_req: channel %d: bad channel", id);
if (session_ident == -1) {
error("client_input_channel_req: no channel %d", id);
} else if (id != session_ident) {
error("client_input_channel_req: bad channel %d != %d",
id, session_ident);
} else if (strcmp(rtype, "exit-status") == 0) {
success = 1;
exit_status = packet_get_int();
packet_done();
}
if (reply) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
packet_send();
}
xfree(rtype);
}
void
client_set_session_ident(int id)
{
debug2("client_set_session_ident: id %d", id);
session_ident = id;
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
client_input_channel_req, (void *)0);
}

View File

@ -0,0 +1,39 @@
/* $OpenBSD: clientloop.h,v 1.4 2001/02/06 22:43:02 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Client side main loop for the interactive session. */
int client_loop(int have_pty, int escape_char, int id);

View File

@ -12,14 +12,17 @@
*/
#include "includes.h"
RCSID("$OpenBSD: compress.c,v 1.9 2000/09/07 20:27:50 deraadt Exp $");
RCSID("$OpenBSD: compress.c,v 1.14 2001/04/05 10:39:01 markus Exp $");
#include "ssh.h"
#include "log.h"
#include "buffer.h"
#include "zlib.h"
#include "compress.h"
static z_stream incoming_stream;
static z_stream outgoing_stream;
static int compress_init_send_called = 0;
static int compress_init_recv_called = 0;
/*
* Initializes compression; level is compression level from 1 to 9
@ -27,19 +30,29 @@ static z_stream outgoing_stream;
*/
void
buffer_compress_init(int level)
buffer_compress_init_send(int level)
{
if (compress_init_send_called == 1)
deflateEnd(&incoming_stream);
compress_init_send_called = 1;
debug("Enabling compression at level %d.", level);
if (level < 1 || level > 9)
fatal("Bad compression level %d.", level);
inflateInit(&incoming_stream);
deflateInit(&outgoing_stream, level);
}
void
buffer_compress_init_recv(void)
{
if (compress_init_recv_called == 1)
inflateEnd(&incoming_stream);
compress_init_recv_called = 1;
inflateInit(&incoming_stream);
}
/* Frees any data structures allocated for compression. */
void
buffer_compress_uninit()
buffer_compress_uninit(void)
{
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
outgoing_stream.total_in, outgoing_stream.total_out,
@ -49,8 +62,10 @@ buffer_compress_uninit()
incoming_stream.total_out, incoming_stream.total_in,
incoming_stream.total_out == 0 ? 0.0 :
(double) incoming_stream.total_in / incoming_stream.total_out);
inflateEnd(&incoming_stream);
deflateEnd(&outgoing_stream);
if (compress_init_recv_called == 1)
inflateEnd(&incoming_stream);
if (compress_init_send_called == 1)
deflateEnd(&outgoing_stream);
}
/*
@ -73,13 +88,13 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
return;
/* Input is the contents of the input buffer. */
outgoing_stream.next_in = (unsigned char *) buffer_ptr(input_buffer);
outgoing_stream.next_in = (u_char *) buffer_ptr(input_buffer);
outgoing_stream.avail_in = buffer_len(input_buffer);
/* Loop compressing until deflate() returns with avail_out != 0. */
do {
/* Set up fixed-size output buffer. */
outgoing_stream.next_out = (unsigned char *)buf;
outgoing_stream.next_out = (u_char *)buf;
outgoing_stream.avail_out = sizeof(buf);
/* Compress as much data into the buffer as possible. */
@ -112,12 +127,12 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
char buf[4096];
int status;
incoming_stream.next_in = (unsigned char *) buffer_ptr(input_buffer);
incoming_stream.next_in = (u_char *) buffer_ptr(input_buffer);
incoming_stream.avail_in = buffer_len(input_buffer);
for (;;) {
/* Set up fixed-size output buffer. */
incoming_stream.next_out = (unsigned char *) buf;
incoming_stream.next_out = (u_char *) buf;
incoming_stream.avail_out = sizeof(buf);
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);

View File

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: compress.h,v 1.6 2000/09/07 20:27:50 deraadt Exp $"); */
/* RCSID("$OpenBSD: compress.h,v 1.8 2001/04/05 10:39:02 markus Exp $"); */
#ifndef COMPRESS_H
#define COMPRESS_H
@ -20,10 +20,11 @@
* Initializes compression; level is compression level from 1 to 9 (as in
* gzip).
*/
void buffer_compress_init(int level);
void buffer_compress_init_send(int level);
void buffer_compress_init_recv(void);
/* Frees any data structures allocated by buffer_compress_init. */
void buffer_compress_uninit();
void buffer_compress_uninit(void);
/*
* Compresses the contents of input_buffer into output_buffer. All packets

View File

@ -31,7 +31,7 @@
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* logic; the shift must be u_(bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
@ -39,11 +39,11 @@
#include "includes.h"
RCSID("$OpenBSD: crc32.c,v 1.7 2000/09/07 20:27:51 deraadt Exp $");
RCSID("$OpenBSD: crc32.c,v 1.8 2000/12/19 23:17:56 markus Exp $");
#include "crc32.h"
static unsigned int crc32_tab[] = {
static u_int crc32_tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
@ -100,11 +100,11 @@ static unsigned int crc32_tab[] = {
/* Return a 32-bit CRC of the contents of the buffer. */
unsigned int
ssh_crc32(const unsigned char *s, unsigned int len)
u_int
ssh_crc32(const u_char *s, u_int len)
{
unsigned int i;
unsigned int crc32val;
u_int i;
u_int crc32val;
crc32val = 0;
for (i = 0; i < len; i ++) {

View File

@ -1,6 +1,6 @@
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
* Copyright (c) 1992 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions for computing 32-bit CRC.
*
@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: crc32.h,v 1.8 2000/09/07 20:27:51 deraadt Exp $"); */
/* RCSID("$OpenBSD: crc32.h,v 1.10 2001/03/02 18:54:31 deraadt Exp $"); */
#ifndef CRC32_H
#define CRC32_H
@ -20,6 +20,6 @@
* This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
* The polynomial used is 0xedb88320.
*/
unsigned int ssh_crc32(const unsigned char *buf, unsigned int len);
u_int ssh_crc32(const u_char *buf, u_int len);
#endif /* CRC32_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: deattack.c,v 1.10 2000/10/31 13:18:53 markus Exp $ */
/* $OpenBSD: deattack.c,v 1.13 2001/03/01 02:45:10 deraadt Exp $ */
/*
* Cryptographic attack detector for ssh - source code
@ -21,7 +21,7 @@
#include "includes.h"
#include "deattack.h"
#include "ssh.h"
#include "log.h"
#include "crc32.h"
#include "getput.h"
#include "xmalloc.h"
@ -44,23 +44,23 @@
/* Hash function (Input keys are cipher results) */
#define HASH(x) GET_32BIT(x)
#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE))
#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
void
crc_update(u_int32_t *a, u_int32_t b)
{
b ^= *a;
*a = ssh_crc32((unsigned char *) &b, sizeof(b));
*a = ssh_crc32((u_char *) &b, sizeof(b));
}
/* detect if a block is used in a particular pattern */
int
check_crc(unsigned char *S, unsigned char *buf, u_int32_t len,
unsigned char *IV)
check_crc(u_char *S, u_char *buf, u_int32_t len,
u_char *IV)
{
u_int32_t crc;
unsigned char *c;
u_char *c;
crc = 0;
if (IV && !CMP(S, IV)) {
@ -82,14 +82,14 @@ check_crc(unsigned char *S, unsigned char *buf, u_int32_t len,
/* Detect a crc32 compensation attack on a packet */
int
detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
detect_attack(u_char *buf, u_int32_t len, u_char *IV)
{
static u_int16_t *h = (u_int16_t *) NULL;
static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
register u_int32_t i, j;
u_int32_t l;
register unsigned char *c;
unsigned char *d;
register u_char *c;
u_char *d;
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
len % SSH_BLOCKSIZE != 0) {

View File

@ -1,3 +1,5 @@
/* $OpenBSD: deattack.h,v 1.5 2001/01/29 01:58:15 niklas Exp $ */
/*
* Cryptographic attack detector for ssh - Header file
*
@ -24,5 +26,5 @@
#define DEATTACK_OK 0
#define DEATTACK_DETECTED 1
int detect_attack(unsigned char *buf, u_int32_t len, unsigned char IV[8]);
int detect_attack(u_char *buf, u_int32_t len, u_char IV[8]);
#endif

View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $");
RCSID("$OpenBSD: dh.c,v 1.14 2001/04/15 08:43:45 markus Exp $");
#include "xmalloc.h"
@ -31,10 +31,13 @@ RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $");
#include <openssl/dh.h>
#include <openssl/evp.h>
#include "ssh.h"
#include "buffer.h"
#include "cipher.h"
#include "kex.h"
#include "dh.h"
#include "pathnames.h"
#include "log.h"
#include "misc.h"
int
parse_prime(int linenum, char *line, struct dhgroup *dhg)
@ -66,6 +69,8 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
if (cp == NULL || *strsize == '\0' ||
(dhg->size = atoi(strsize)) == 0)
goto fail;
/* The whole group is one bit larger */
dhg->size++;
gen = strsep(&cp, " "); /* gen */
if (cp == NULL || *gen == '\0')
goto fail;
@ -74,25 +79,28 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
goto fail;
dhg->g = BN_new();
if (BN_hex2bn(&dhg->g, gen) < 0) {
BN_free(dhg->g);
goto fail;
}
dhg->p = BN_new();
if (BN_hex2bn(&dhg->p, prime) < 0) {
BN_free(dhg->g);
BN_free(dhg->p);
goto fail;
}
if (BN_hex2bn(&dhg->g, gen) == 0)
goto failclean;
if (BN_hex2bn(&dhg->p, prime) == 0)
goto failclean;
if (BN_num_bits(dhg->p) != dhg->size)
goto failclean;
return (1);
failclean:
BN_free(dhg->g);
BN_free(dhg->p);
fail:
fprintf(stderr, "Bad prime description in line %d\n", linenum);
error("Bad prime description in line %d", linenum);
return (0);
}
DH *
choose_dh(int minbits)
choose_dh(int min, int wantbits, int max)
{
FILE *f;
char line[1024];
@ -100,10 +108,9 @@ choose_dh(int minbits)
int linenum;
struct dhgroup dhg;
f = fopen(DH_PRIMES, "r");
f = fopen(_PATH_DH_PRIMES, "r");
if (!f) {
perror(DH_PRIMES);
log("WARNING: %s does not exist, using old prime", DH_PRIMES);
log("WARNING: %s does not exist, using old prime", _PATH_DH_PRIMES);
return (dh_new_group1());
}
@ -116,8 +123,11 @@ choose_dh(int minbits)
BN_free(dhg.g);
BN_free(dhg.p);
if ((dhg.size > minbits && dhg.size < best) ||
(dhg.size > best && best < minbits)) {
if (dhg.size > max || dhg.size < min)
continue;
if ((dhg.size > wantbits && dhg.size < best) ||
(dhg.size > best && best < wantbits)) {
best = dhg.size;
bestcount = 0;
}
@ -127,14 +137,13 @@ choose_dh(int minbits)
fclose (f);
if (bestcount == 0) {
log("WARNING: no primes in %s, using old prime", DH_PRIMES);
return (dh_new_group1());
log("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
return (NULL);
}
f = fopen(DH_PRIMES, "r");
f = fopen(_PATH_DH_PRIMES, "r");
if (!f) {
perror(DH_PRIMES);
exit(1);
fatal("WARNING: %s disappeared, giving up", _PATH_DH_PRIMES);
}
linenum = 0;
@ -142,9 +151,9 @@ choose_dh(int minbits)
while (fgets(line, sizeof(line), f)) {
if (!parse_prime(linenum, line, &dhg))
continue;
if (dhg.size != best)
continue;
if (linenum++ != which) {
if ((dhg.size > max || dhg.size < min) ||
dhg.size != best ||
linenum++ != which) {
BN_free(dhg.g);
BN_free(dhg.p);
continue;
@ -152,6 +161,134 @@ choose_dh(int minbits)
break;
}
fclose(f);
if (linenum != which+1)
fatal("WARNING: line %d disappeared in %s, giving up",
which, _PATH_DH_PRIMES);
return (dh_new_group(dhg.g, dhg.p));
}
/* diffie-hellman-group1-sha1 */
int
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
{
int i;
int n = BN_num_bits(dh_pub);
int bits_set = 0;
if (dh_pub->neg) {
log("invalid public DH value: negativ");
return 0;
}
for (i = 0; i <= n; i++)
if (BN_is_bit_set(dh_pub, i))
bits_set++;
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
return 1;
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
return 0;
}
void
dh_gen_key(DH *dh, int need)
{
int i, bits_set = 0, tries = 0;
if (dh->p == NULL)
fatal("dh_gen_key: dh->p == NULL");
if (2*need >= BN_num_bits(dh->p))
fatal("dh_gen_key: group too small: %d (2*need %d)",
BN_num_bits(dh->p), 2*need);
do {
if (dh->priv_key != NULL)
BN_free(dh->priv_key);
dh->priv_key = BN_new();
if (dh->priv_key == NULL)
fatal("dh_gen_key: BN_new failed");
/* generate a 2*need bits random private exponent */
if (!BN_rand(dh->priv_key, 2*need, 0, 0))
fatal("dh_gen_key: BN_rand failed");
if (DH_generate_key(dh) == 0)
fatal("DH_generate_key");
for (i = 0; i <= BN_num_bits(dh->priv_key); i++)
if (BN_is_bit_set(dh->priv_key, i))
bits_set++;
debug("dh_gen_key: priv key bits set: %d/%d",
bits_set, BN_num_bits(dh->priv_key));
if (tries++ > 10)
fatal("dh_gen_key: too many bad keys: giving up");
} while (!dh_pub_is_valid(dh, dh->pub_key));
}
DH *
dh_new_group_asc(const char *gen, const char *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
if (BN_hex2bn(&dh->p, modulus) == 0)
fatal("BN_hex2bn p");
if (BN_hex2bn(&dh->g, gen) == 0)
fatal("BN_hex2bn g");
return (dh);
}
/*
* This just returns the group, we still need to generate the exchange
* value.
*/
DH *
dh_new_group(BIGNUM *gen, BIGNUM *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
dh->p = modulus;
dh->g = gen;
return (dh);
}
DH *
dh_new_group1(void)
{
static char *gen = "2", *group1 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
"FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group1));
}
/*
* Estimates the group order for a Diffie-Hellman group that has an
* attack complexity approximately the same as O(2**bits). Estimate
* with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
*/
int
dh_estimate(int bits)
{
if (bits < 64)
return (512); /* O(2**63) */
if (bits < 128)
return (1024); /* O(2**86) */
if (bits < 192)
return (2048); /* O(2**116) */
return (4096); /* O(2**156) */
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: dh.h,v 1.5 2001/04/03 19:53:29 markus Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
*
@ -30,6 +32,17 @@ struct dhgroup {
BIGNUM *p;
};
DH *choose_dh(int minbits);
DH *choose_dh(int min, int nbits, int max);
DH *dh_new_group_asc(const char *, const char *);
DH *dh_new_group(BIGNUM *, BIGNUM *);
DH *dh_new_group1(void);
void dh_gen_key(DH *, int);
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
int dh_estimate(int bits);
#define DH_GRP_MIN 1024
#define DH_GRP_MAX 8192
#endif

View File

@ -22,10 +22,14 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: dispatch.c,v 1.5 2000/09/21 11:25:34 markus Exp $");
#include "ssh.h"
RCSID("$OpenBSD: dispatch.c,v 1.10 2001/02/18 18:33:53 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
#include "log.h"
#include "dispatch.h"
#include "packet.h"
#include "compat.h"
#define DISPATCH_MIN 0
#define DISPATCH_MAX 255
@ -36,6 +40,8 @@ void
dispatch_protocol_error(int type, int plen, void *ctxt)
{
error("Hm, dispatch protocol error: type %d plen %d", type, plen);
if (compat20 && type == SSH2_MSG_KEXINIT)
fatal("dispatch_protocol_error: rekeying is not supported");
}
void
dispatch_init(dispatch_fn *dflt)
@ -66,7 +72,7 @@ dispatch_run(int mode, int *done, void *ctxt)
if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
(*dispatch[type])(type, plen, ctxt);
else
packet_disconnect("protocol error: rcvd type %d", type);
packet_disconnect("protocol error: rcvd type %d", type);
if (done != NULL && *done)
return;
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: dispatch.h,v 1.4 2001/01/29 01:58:15 niklas Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*

View File

@ -11,20 +11,39 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: getput.h,v 1.5 2000/09/07 20:27:51 deraadt Exp $"); */
/* RCSID("$OpenBSD: getput.h,v 1.7 2001/01/10 22:56:22 markus Exp $"); */
#ifndef GETPUT_H
#define GETPUT_H
/*------------ macros for storing/extracting msb first words -------------*/
#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \
((unsigned long)(unsigned char)(cp)[1] << 16) | \
((unsigned long)(unsigned char)(cp)[2] << 8) | \
((unsigned long)(unsigned char)(cp)[3]))
#define GET_64BIT(cp) (((u_int64_t)(u_char)(cp)[0] << 56) | \
((u_int64_t)(u_char)(cp)[1] << 48) | \
((u_int64_t)(u_char)(cp)[2] << 40) | \
((u_int64_t)(u_char)(cp)[3] << 32) | \
((u_int64_t)(u_char)(cp)[4] << 24) | \
((u_int64_t)(u_char)(cp)[5] << 16) | \
((u_int64_t)(u_char)(cp)[6] << 8) | \
((u_int64_t)(u_char)(cp)[7]))
#define GET_16BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 8) | \
((unsigned long)(unsigned char)(cp)[1]))
#define GET_32BIT(cp) (((u_long)(u_char)(cp)[0] << 24) | \
((u_long)(u_char)(cp)[1] << 16) | \
((u_long)(u_char)(cp)[2] << 8) | \
((u_long)(u_char)(cp)[3]))
#define GET_16BIT(cp) (((u_long)(u_char)(cp)[0] << 8) | \
((u_long)(u_char)(cp)[1]))
#define PUT_64BIT(cp, value) do { \
(cp)[0] = (value) >> 56; \
(cp)[1] = (value) >> 48; \
(cp)[2] = (value) >> 40; \
(cp)[3] = (value) >> 32; \
(cp)[4] = (value) >> 24; \
(cp)[5] = (value) >> 16; \
(cp)[6] = (value) >> 8; \
(cp)[7] = (value); } while (0)
#define PUT_32BIT(cp, value) do { \
(cp)[0] = (value) >> 24; \
@ -36,26 +55,4 @@
(cp)[0] = (value) >> 8; \
(cp)[1] = (value); } while (0)
/*------------ macros for storing/extracting lsb first words -------------*/
#define GET_32BIT_LSB_FIRST(cp) \
(((unsigned long)(unsigned char)(cp)[0]) | \
((unsigned long)(unsigned char)(cp)[1] << 8) | \
((unsigned long)(unsigned char)(cp)[2] << 16) | \
((unsigned long)(unsigned char)(cp)[3] << 24))
#define GET_16BIT_LSB_FIRST(cp) \
(((unsigned long)(unsigned char)(cp)[0]) | \
((unsigned long)(unsigned char)(cp)[1] << 8))
#define PUT_32BIT_LSB_FIRST(cp, value) do { \
(cp)[0] = (value); \
(cp)[1] = (value) >> 8; \
(cp)[2] = (value) >> 16; \
(cp)[3] = (value) >> 24; } while (0)
#define PUT_16BIT_LSB_FIRST(cp, value) do { \
(cp)[0] = (value); \
(cp)[1] = (value) >> 8; } while (0)
#endif /* GETPUT_H */

View File

@ -0,0 +1,78 @@
/* $OpenBSD: groupaccess.c,v 1.3 2001/01/29 01:58:15 niklas Exp $ */
/*
* Copyright (c) 2001 Kevin Steves. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include "groupaccess.h"
#include "xmalloc.h"
#include "match.h"
#include "log.h"
static int ngroups;
static char *groups_byname[NGROUPS_MAX + 1]; /* +1 for base/primary group */
int
ga_init(const char *user, gid_t base)
{
gid_t groups_bygid[NGROUPS_MAX + 1];
int i, j;
struct group *gr;
if (ngroups > 0)
ga_free();
ngroups = sizeof(groups_bygid) / sizeof(gid_t);
if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
log("getgrouplist: groups list too small");
for (i = 0, j = 0; i < ngroups; i++)
if ((gr = getgrgid(groups_bygid[i])) != NULL)
groups_byname[j++] = xstrdup(gr->gr_name);
return (ngroups = j);
}
int
ga_match(char * const *groups, int n)
{
int i, j;
for (i = 0; i < ngroups; i++)
for (j = 0; j < n; j++)
if (match_pattern(groups_byname[i], groups[j]))
return 1;
return 0;
}
void
ga_free(void)
{
int i;
if (ngroups > 0) {
for (i = 0; i < ngroups; i++)
xfree(groups_byname[i]);
ngroups = 0;
}
}

View File

@ -0,0 +1,49 @@
/* $OpenBSD: groupaccess.h,v 1.2 2001/01/29 01:58:15 niklas Exp $ */
/*
* Copyright (c) 2001 Kevin Steves. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GROUPACCESS_H
#define GROUPACCESS_H
#include <grp.h>
/*
* Initialize group access list for user with primary (base) and
* supplementary groups. Return the number of groups in the list.
*/
int ga_init(const char *user, gid_t base);
/*
* Return 1 if one of user's groups is contained in groups.
* Return 0 otherwise. Use match_pattern() for string comparison.
*/
int ga_match(char * const *groups, int ngroups);
/*
* Free memory allocated for group access list.
*/
void ga_free(void);
#endif

View File

@ -1,3 +1,5 @@
/* $OpenBSD: hostfile.h,v 1.7 2001/02/08 19:30:51 itojun Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -12,6 +14,9 @@
#ifndef HOSTFILE_H
#define HOSTFILE_H
int
auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n);
/*
* Checks whether the given host is already in the list of our known hosts.
* Returns HOST_OK if the host is known and has the specified key, HOST_NEW
@ -21,8 +26,10 @@
typedef enum {
HOST_OK, HOST_NEW, HOST_CHANGED
} HostStatus;
HostStatus
check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found);
check_host_in_hostfile(const char *filename, const char *host, Key *key,
Key *found, int *line);
/*
* Appends an entry to the host file. Returns false if the entry could not

View File

@ -23,375 +23,217 @@
*/
#include "includes.h"
RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $");
RCSID("$OpenBSD: kex.c,v 1.33 2001/04/05 10:42:50 markus Exp $");
#include <openssl/crypto.h>
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "packet.h"
#include "compat.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/pem.h>
#include "cipher.h"
#include "kex.h"
#include "key.h"
#include "log.h"
#include "mac.h"
#include "match.h"
#include "dispatch.h"
#define KEX_COOKIE_LEN 16
Buffer *
kex_init(char *myproposal[PROPOSAL_MAX])
void kex_kexinit_finish(Kex *kex);
void kex_choose_conf(Kex *k);
/* put algorithm proposal into buffer */
void
kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
{
int first_kex_packet_follows = 0;
unsigned char cookie[KEX_COOKIE_LEN];
u_int32_t rand = 0;
int i;
Buffer *ki = xmalloc(sizeof(*ki));
buffer_clear(b);
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if (i % 4 == 0)
rand = arc4random();
cookie[i] = rand & 0xff;
buffer_put_char(b, rand & 0xff);
rand >>= 8;
}
buffer_init(ki);
buffer_append(ki, (char *)cookie, sizeof cookie);
for (i = 0; i < PROPOSAL_MAX; i++)
buffer_put_cstring(ki, myproposal[i]);
buffer_put_char(ki, first_kex_packet_follows);
buffer_put_int(ki, 0); /* uint32 reserved */
return ki;
buffer_put_cstring(b, proposal[i]);
buffer_put_char(b, 0); /* first_kex_packet_follows */
buffer_put_int(b, 0); /* uint32 reserved */
}
/* send kexinit, parse and save reply */
void
kex_exchange_kexinit(
Buffer *my_kexinit, Buffer *peer_kexint,
char *peer_proposal[PROPOSAL_MAX])
/* parse buffer and return algorithm proposal */
char **
kex_buf2prop(Buffer *raw)
{
Buffer b;
int i;
char *ptr;
int plen;
char **proposal;
debug("send KEXINIT");
packet_start(SSH2_MSG_KEXINIT);
packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
packet_send();
packet_write_wait();
debug("done");
proposal = xmalloc(PROPOSAL_MAX * sizeof(char *));
/*
* read and save raw KEXINIT payload in buffer. this is used during
* computation of the session_id and the session keys.
*/
debug("wait KEXINIT");
packet_read_expect(&plen, SSH2_MSG_KEXINIT);
ptr = packet_get_raw(&plen);
buffer_append(peer_kexint, ptr, plen);
/* parse packet and save algorithm proposal */
buffer_init(&b);
buffer_append(&b, buffer_ptr(raw), buffer_len(raw));
/* skip cookie */
for (i = 0; i < KEX_COOKIE_LEN; i++)
packet_get_char();
buffer_get_char(&b);
/* extract kex init proposal strings */
for (i = 0; i < PROPOSAL_MAX; i++) {
peer_proposal[i] = packet_get_string(NULL);
debug("got kexinit: %s", peer_proposal[i]);
proposal[i] = buffer_get_string(&b,NULL);
debug2("kex_parse_kexinit: %s", proposal[i]);
}
/* first kex follow / reserved */
i = packet_get_char();
debug("first kex follow: %d ", i);
i = packet_get_int();
debug("reserved: %d ", i);
packet_done();
debug("done");
}
/* diffie-hellman-group1-sha1 */
int
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
{
int i;
int n = BN_num_bits(dh_pub);
int bits_set = 0;
if (dh_pub->neg) {
log("invalid public DH value: negativ");
return 0;
}
for (i = 0; i <= n; i++)
if (BN_is_bit_set(dh_pub, i))
bits_set++;
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
return 1;
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
return 0;
}
DH *
dh_gen_key(DH *dh)
{
int tries = 0;
do {
if (DH_generate_key(dh) == 0)
fatal("DH_generate_key");
if (tries++ > 10)
fatal("dh_new_group1: too many bad keys: giving up");
} while (!dh_pub_is_valid(dh, dh->pub_key));
return dh;
}
DH *
dh_new_group_asc(const char *gen, const char *modulus)
{
DH *dh;
int ret;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
fatal("BN_hex2bn p");
if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
fatal("BN_hex2bn g");
return (dh_gen_key(dh));
}
DH *
dh_new_group(BIGNUM *gen, BIGNUM *modulus)
{
DH *dh;
dh = DH_new();
if (dh == NULL)
fatal("DH_new");
dh->p = modulus;
dh->g = gen;
return (dh_gen_key(dh));
}
DH *
dh_new_group1()
{
static char *gen = "2", *group1 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
"FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group1));
/* first kex follows / reserved */
i = buffer_get_char(&b);
debug2("kex_parse_kexinit: first_kex_follows %d ", i);
i = buffer_get_int(&b);
debug2("kex_parse_kexinit: reserved %d ", i);
buffer_free(&b);
return proposal;
}
void
dump_digest(unsigned char *digest, int len)
kex_prop_free(char **proposal)
{
int i;
for (i = 0; i< len; i++){
fprintf(stderr, "%02x", digest[i]);
if(i%2!=0)
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
for (i = 0; i < PROPOSAL_MAX; i++)
xfree(proposal[i]);
xfree(proposal);
}
unsigned char *
kex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
void
kex_protocol_error(int type, int plen, void *ctxt)
{
Buffer b;
static unsigned char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
buffer_init(&b);
buffer_put_string(&b, client_version_string, strlen(client_version_string));
buffer_put_string(&b, server_version_string, strlen(server_version_string));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEX
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest(digest, evp_md->md_size);
#endif
return digest;
error("Hm, kex protocol error: type %d plen %d", type, plen);
}
unsigned char *
kex_hash_gex(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
int minbits, BIGNUM *prime, BIGNUM *gen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
void
kex_clear_dispatch(void)
{
Buffer b;
static unsigned char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
int i;
buffer_init(&b);
buffer_put_string(&b, client_version_string, strlen(client_version_string));
buffer_put_string(&b, server_version_string, strlen(server_version_string));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_int(&b, minbits);
buffer_put_bignum2(&b, prime);
buffer_put_bignum2(&b, gen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEX
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest(digest, evp_md->md_size);
#endif
return digest;
/* Numbers 30-49 are used for kex packets */
for (i = 30; i <= 49; i++)
dispatch_set(i, &kex_protocol_error);
}
unsigned char *
derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
void
kex_finish(Kex *kex)
{
Buffer b;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
char c = id;
int have;
int mdsz = evp_md->md_size;
unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
int plen;
buffer_init(&b);
buffer_put_bignum2(&b, shared_secret);
kex_clear_dispatch();
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
EVP_DigestUpdate(&md, &c, 1); /* key id */
EVP_DigestUpdate(&md, hash, mdsz); /* session id */
EVP_DigestFinal(&md, digest, NULL);
packet_start(SSH2_MSG_NEWKEYS);
packet_send();
/* packet_write_wait(); */
debug("SSH2_MSG_NEWKEYS sent");
/* expand */
for (have = mdsz; need > have; have += mdsz) {
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestUpdate(&md, hash, mdsz);
EVP_DigestUpdate(&md, digest, have);
EVP_DigestFinal(&md, digest + have, NULL);
}
buffer_free(&b);
#ifdef DEBUG_KEX
fprintf(stderr, "Digest '%c'== ", c);
dump_digest(digest, need);
#endif
return digest;
debug("waiting for SSH2_MSG_NEWKEYS");
packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
debug("SSH2_MSG_NEWKEYS received");
kex->done = 1;
buffer_clear(&kex->peer);
/* buffer_clear(&kex->my); */
kex->flags &= ~KEX_INIT_SENT;
xfree(kex->name);
kex->name = NULL;
}
#define NKEYS 6
#define MAX_PROP 20
#define SEP ","
char *
get_match(char *client, char *server)
void
kex_send_kexinit(Kex *kex)
{
char *sproposals[MAX_PROP];
char *c, *s, *p, *ret, *cp, *sp;
int i, j, nproposals;
c = cp = xstrdup(client);
s = sp = xstrdup(server);
for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
(p = strsep(&sp, SEP)), i++) {
if (i < MAX_PROP)
sproposals[i] = p;
else
break;
if (kex == NULL) {
error("kex_send_kexinit: no kex, cannot rekey");
return;
}
nproposals = i;
for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
(p = strsep(&cp, SEP)), i++) {
for (j = 0; j < nproposals; j++) {
if (strcmp(p, sproposals[j]) == 0) {
ret = xstrdup(p);
xfree(c);
xfree(s);
return ret;
}
}
if (kex->flags & KEX_INIT_SENT) {
debug("KEX_INIT_SENT");
return;
}
xfree(c);
xfree(s);
return NULL;
kex->done = 0;
packet_start(SSH2_MSG_KEXINIT);
packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my));
packet_send();
debug("SSH2_MSG_KEXINIT sent");
kex->flags |= KEX_INIT_SENT;
}
void
kex_input_kexinit(int type, int plen, void *ctxt)
{
char *ptr;
int dlen;
int i;
Kex *kex = (Kex *)ctxt;
debug("SSH2_MSG_KEXINIT received");
if (kex == NULL)
fatal("kex_input_kexinit: no kex, cannot rekey");
ptr = packet_get_raw(&dlen);
buffer_append(&kex->peer, ptr, dlen);
/* discard packet */
for (i = 0; i < KEX_COOKIE_LEN; i++)
packet_get_char();
for (i = 0; i < PROPOSAL_MAX; i++)
xfree(packet_get_string(NULL));
packet_get_char();
packet_get_int();
packet_done();
kex_kexinit_finish(kex);
}
Kex *
kex_setup(char *proposal[PROPOSAL_MAX])
{
Kex *kex;
kex = xmalloc(sizeof(*kex));
memset(kex, 0, sizeof(*kex));
buffer_init(&kex->peer);
buffer_init(&kex->my);
kex_prop2buf(&kex->my, proposal);
kex->done = 0;
kex_send_kexinit(kex); /* we start */
kex_clear_dispatch();
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
return kex;
}
void
kex_kexinit_finish(Kex *kex)
{
if (!(kex->flags & KEX_INIT_SENT))
kex_send_kexinit(kex);
kex_choose_conf(kex);
switch(kex->kex_type) {
case DH_GRP1_SHA1:
kexdh(kex);
break;
case DH_GEX_SHA1:
kexgex(kex);
break;
default:
fatal("Unsupported key exchange %d", kex->kex_type);
}
}
void
choose_enc(Enc *enc, char *client, char *server)
{
char *name = get_match(client, server);
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching cipher found: client %s server %s", client, server);
enc->cipher = cipher_by_name(name);
@ -405,28 +247,22 @@ choose_enc(Enc *enc, char *client, char *server)
void
choose_mac(Mac *mac, char *client, char *server)
{
char *name = get_match(client, server);
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching mac found: client %s server %s", client, server);
if (strcmp(name, "hmac-md5") == 0) {
mac->md = EVP_md5();
} else if (strcmp(name, "hmac-sha1") == 0) {
mac->md = EVP_sha1();
} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
mac->md = EVP_ripemd160();
} else {
if (mac_init(mac, name) < 0)
fatal("unsupported mac %s", name);
}
/* truncate the key */
if (datafellows & SSH_BUG_HMAC)
mac->key_len = 16;
mac->name = name;
mac->mac_len = mac->md->md_size;
mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
mac->key = NULL;
mac->enabled = 0;
}
void
choose_comp(Comp *comp, char *client, char *server)
{
char *name = get_match(client, server);
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching comp found: client %s server %s", client, server);
if (strcmp(name, "zlib") == 0) {
@ -441,7 +277,7 @@ choose_comp(Comp *comp, char *client, char *server)
void
choose_kex(Kex *k, char *client, char *server)
{
k->name = get_match(client, server);
k->name = match_list(client, server, NULL);
if (k->name == NULL)
fatal("no kex alg");
if (strcmp(k->name, KEX_DH1) == 0) {
@ -454,73 +290,164 @@ choose_kex(Kex *k, char *client, char *server)
void
choose_hostkeyalg(Kex *k, char *client, char *server)
{
k->hostkeyalg = get_match(client, server);
if (k->hostkeyalg == NULL)
char *hostkeyalg = match_list(client, server, NULL);
if (hostkeyalg == NULL)
fatal("no hostkey alg");
if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
fatal("bad hostkey alg %s", k->hostkeyalg);
k->hostkey_type = key_type_from_name(hostkeyalg);
if (k->hostkey_type == KEY_UNSPEC)
fatal("bad hostkey alg '%s'", hostkeyalg);
xfree(hostkeyalg);
}
Kex *
kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
void
kex_choose_conf(Kex *kex)
{
Newkeys *newkeys;
char **my, **peer;
char **cprop, **sprop;
int nenc, nmac, ncomp;
int mode;
int ctos; /* direction: if true client-to-server */
int need;
Kex *k;
k = xmalloc(sizeof(*k));
memset(k, 0, sizeof(*k));
k->server = server;
my = kex_buf2prop(&kex->my);
peer = kex_buf2prop(&kex->peer);
if (kex->server) {
cprop=peer;
sprop=my;
} else {
cprop=my;
sprop=peer;
}
/* Algorithm Negotiation */
for (mode = 0; mode < MODE_MAX; mode++) {
int nenc, nmac, ncomp;
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
newkeys = xmalloc(sizeof(*newkeys));
memset(newkeys, 0, sizeof(*newkeys));
kex->newkeys[mode] = newkeys;
ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]);
choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]);
choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]);
debug("kex: %s %s %s %s",
ctos ? "client->server" : "server->client",
k->enc[mode].name,
k->mac[mode].name,
k->comp[mode].name);
newkeys->enc.name,
newkeys->mac.name,
newkeys->comp.name);
}
choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
if (need < k->enc[mode].cipher->key_len)
need = k->enc[mode].cipher->key_len;
if (need < k->enc[mode].cipher->block_size)
need = k->enc[mode].cipher->block_size;
if (need < k->mac[mode].key_len)
need = k->mac[mode].key_len;
newkeys = kex->newkeys[mode];
if (need < newkeys->enc.cipher->key_len)
need = newkeys->enc.cipher->key_len;
if (need < newkeys->enc.cipher->block_size)
need = newkeys->enc.cipher->block_size;
if (need < newkeys->mac.key_len)
need = newkeys->mac.key_len;
}
/* XXX need runden? */
k->we_need = need;
return k;
kex->we_need = need;
kex_prop_free(my);
kex_prop_free(peer);
}
int
kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
u_char *
derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret)
{
int i;
int mode;
int ctos;
unsigned char *keys[NKEYS];
Buffer b;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
char c = id;
int have;
int mdsz = evp_md->md_size;
u_char *digest = xmalloc(roundup(need, mdsz));
buffer_init(&b);
buffer_put_bignum2(&b, shared_secret);
/* K1 = HASH(K || H || "A" || session_id) */
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestUpdate(&md, hash, mdsz);
EVP_DigestUpdate(&md, &c, 1);
EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len);
EVP_DigestFinal(&md, digest, NULL);
/*
* expand key:
* Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
* Key = K1 || K2 || ... || Kn
*/
for (have = mdsz; need > have; have += mdsz) {
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestUpdate(&md, hash, mdsz);
EVP_DigestUpdate(&md, digest, have);
EVP_DigestFinal(&md, digest + have, NULL);
}
buffer_free(&b);
#ifdef DEBUG_KEX
fprintf(stderr, "key '%c'== ", c);
dump_digest("key", digest, need);
#endif
return digest;
}
Newkeys *current_keys[MODE_MAX];
#define NKEYS 6
void
kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret)
{
u_char *keys[NKEYS];
int i, mode, ctos;
for (i = 0; i < NKEYS; i++)
keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret);
debug("kex_derive_keys");
for (mode = 0; mode < MODE_MAX; mode++) {
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
k->enc[mode].iv = keys[ctos ? 0 : 1];
k->enc[mode].key = keys[ctos ? 2 : 3];
k->mac[mode].key = keys[ctos ? 4 : 5];
current_keys[mode] = kex->newkeys[mode];
kex->newkeys[mode] = NULL;
ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN);
current_keys[mode]->enc.iv = keys[ctos ? 0 : 1];
current_keys[mode]->enc.key = keys[ctos ? 2 : 3];
current_keys[mode]->mac.key = keys[ctos ? 4 : 5];
}
return 0;
}
Newkeys *
kex_get_newkeys(int mode)
{
Newkeys *ret;
ret = current_keys[mode];
current_keys[mode] = NULL;
return ret;
}
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
void
dump_digest(char *msg, u_char *digest, int len)
{
int i;
fprintf(stderr, "%s\n", msg);
for (i = 0; i< len; i++){
fprintf(stderr, "%02x", digest[i]);
if (i%32 == 31)
fprintf(stderr, "\n");
else if (i%8 == 7)
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
}
#endif

View File

@ -1,3 +1,5 @@
/* $OpenBSD: kex.h,v 1.22 2001/04/04 20:25:37 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -24,9 +26,13 @@
#ifndef KEX_H
#define KEX_H
#include <openssl/evp.h>
#include "buffer.h"
#include "cipher.h"
#include "key.h"
#define KEX_DH1 "diffie-hellman-group1-sha1"
#define KEX_DHGEX "diffie-hellman-group-exchange-sha1"
#define KEX_DSS "ssh-dss"
enum kex_init_proposals {
PROPOSAL_KEX_ALGS,
@ -52,78 +58,73 @@ enum kex_exchange {
DH_GRP1_SHA1,
DH_GEX_SHA1
};
#define KEX_INIT_SENT 0x0001
typedef struct Kex Kex;
typedef struct Mac Mac;
typedef struct Comp Comp;
typedef struct Enc Enc;
typedef struct Newkeys Newkeys;
struct Enc {
char *name;
Cipher *cipher;
int enabled;
unsigned char *key;
unsigned char *iv;
char *name;
Cipher *cipher;
int enabled;
u_char *key;
u_char *iv;
};
struct Mac {
char *name;
int enabled;
EVP_MD *md;
int mac_len;
unsigned char *key;
int key_len;
char *name;
int enabled;
EVP_MD *md;
int mac_len;
u_char *key;
int key_len;
};
struct Comp {
int type;
int enabled;
char *name;
int type;
int enabled;
char *name;
};
struct Newkeys {
Enc enc;
Mac mac;
Comp comp;
};
struct Kex {
Enc enc [MODE_MAX];
Mac mac [MODE_MAX];
Comp comp[MODE_MAX];
int we_need;
int server;
char *name;
char *hostkeyalg;
int kex_type;
u_char *session_id;
int session_id_len;
Newkeys *newkeys[MODE_MAX];
int we_need;
int server;
char *name;
int hostkey_type;
int kex_type;
Buffer my;
Buffer peer;
int done;
int flags;
char *client_version_string;
char *server_version_string;
int (*check_host_key)(Key *hostkey);
Key *(*load_host_key)(int type);
};
Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
void
kex_exchange_kexinit(
Buffer *my_kexinit, Buffer *peer_kexint,
char *peer_proposal[PROPOSAL_MAX]);
Kex *
kex_choose_conf(char *cprop[PROPOSAL_MAX],
char *sprop[PROPOSAL_MAX], int server);
int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
void packet_set_kex(Kex *k);
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
DH *dh_new_group_asc(const char *, const char *);
DH *dh_new_group(BIGNUM *, BIGNUM *);
DH *dh_new_group1();
Kex *kex_setup(char *proposal[PROPOSAL_MAX]);
void kex_finish(Kex *kex);
unsigned char *
kex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret);
void kex_send_kexinit(Kex *kex);
void kex_input_kexinit(int type, int plen, void *ctxt);
void kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret);
void kexdh(Kex *);
void kexgex(Kex *);
Newkeys *kex_get_newkeys(int mode);
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
void dump_digest(char *msg, u_char *digest, int len);
#endif
unsigned char *
kex_hash_gex(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
int minbits, BIGNUM *prime, BIGNUM *gen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret);
#endif

304
crypto/openssh/kexdh.c Normal file
View File

@ -0,0 +1,304 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: kexdh.c,v 1.3 2001/04/04 09:48:34 markus Exp $");
#include <openssl/crypto.h>
#include <openssl/bn.h>
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "key.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
u_char *
kex_dh_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
{
Buffer b;
static u_char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
buffer_init(&b);
buffer_put_string(&b, client_version_string, strlen(client_version_string));
buffer_put_string(&b, server_version_string, strlen(server_version_string));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEX
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest("hash", digest, evp_md->md_size);
#endif
return digest;
}
/* client */
void
kexdh_client(Kex *kex)
{
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
DH *dh;
Key *server_host_key;
char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash;
u_int klen, kout, slen, sbloblen;
int dlen, plen;
/* generate and send 'e', client DH public key */
dh = dh_new_group1();
dh_gen_key(dh, kex->we_need * 8);
packet_start(SSH2_MSG_KEXDH_INIT);
packet_put_bignum2(dh->pub_key);
packet_send();
debug("sending SSH2_MSG_KEXDH_INIT");
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
debug("expecting SSH2_MSG_KEXDH_REPLY");
packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
/* key, cert */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (kex->check_host_key == NULL)
fatal("cannot check server_host_key");
kex->check_host_key(server_host_key);
/* DH paramter f, server public DH key */
dh_server_pub = BN_new();
if (dh_server_pub == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
BN_print_fp(stderr, dh_server_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
/* signed H */
signature = packet_get_string(&slen);
packet_done();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_server_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
/* calc and verify H */
hash = kex_dh_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
server_host_key_blob, sbloblen,
dh->pub_key,
dh_server_pub,
shared_secret
);
xfree(server_host_key_blob);
BN_free(dh_server_pub);
DH_free(dh);
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
xfree(signature);
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
/* server */
void
kexdh_server(Kex *kex)
{
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
DH *dh;
Key *server_host_key;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, kout;
int dlen, slen, plen;
/* generate server DH public key */
dh = dh_new_group1();
dh_gen_key(dh, kex->we_need * 8);
debug("expecting SSH2_MSG_KEXDH_INIT");
packet_read_expect(&plen, SSH2_MSG_KEXDH_INIT);
if (kex->load_host_key == NULL)
fatal("Cannot load hostkey");
server_host_key = kex->load_host_key(kex->hostkey_type);
if (server_host_key == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
/* key, cert */
dh_client_pub = BN_new();
if (dh_client_pub == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
BN_print_fp(stderr, dh_client_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_client_pub));
#endif
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
if (!dh_pub_is_valid(dh, dh_client_pub))
packet_disconnect("bad client public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_client_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
/* calc H */
hash = kex_dh_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
(char *)server_host_key_blob, sbloblen,
dh_client_pub,
dh->pub_key,
shared_secret
);
BN_free(dh_client_pub);
/* save session id := H */
/* XXX hashlen depends on KEX */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
/* XXX hashlen depends on KEX */
key_sign(server_host_key, &signature, &slen, hash, 20);
/* destroy_sensitive_data(); */
/* send server hostkey, DH pubkey 'f' and singed H */
packet_start(SSH2_MSG_KEXDH_REPLY);
packet_put_string((char *)server_host_key_blob, sbloblen);
packet_put_bignum2(dh->pub_key); /* f */
packet_put_string((char *)signature, slen);
packet_send();
xfree(signature);
xfree(server_host_key_blob);
/* have keys, free DH */
DH_free(dh);
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
void
kexdh(Kex *kex)
{
if (kex->server)
kexdh_server(kex);
else
kexdh_client(kex);
}

408
crypto/openssh/kexgex.c Normal file
View File

@ -0,0 +1,408 @@
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: kexgex.c,v 1.5 2001/04/05 10:42:50 markus Exp $");
#include <openssl/bn.h>
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "key.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
#include "compat.h"
u_char *
kexgex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
{
Buffer b;
static u_char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
buffer_init(&b);
buffer_put_string(&b, client_version_string, strlen(client_version_string));
buffer_put_string(&b, server_version_string, strlen(server_version_string));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
if (min == -1 || max == -1)
buffer_put_int(&b, wantbits);
else {
buffer_put_int(&b, min);
buffer_put_int(&b, wantbits);
buffer_put_int(&b, max);
}
buffer_put_bignum2(&b, prime);
buffer_put_bignum2(&b, gen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEXDH
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEXDH
dump_digest("hash", digest, evp_md->md_size);
#endif
return digest;
}
/* client */
void
kexgex_client(Kex *kex)
{
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
BIGNUM *p = NULL, *g = NULL;
Key *server_host_key;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int klen, kout, slen, sbloblen;
int dlen, plen, min, max, nbits;
DH *dh;
nbits = dh_estimate(kex->we_need * 8);
if (datafellows & SSH_OLD_DHGEX) {
debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
/* Old GEX request */
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
packet_put_int(nbits);
min = DH_GRP_MIN;
max = DH_GRP_MAX;
} else {
debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
/* New GEX request */
min = DH_GRP_MIN;
max = DH_GRP_MAX;
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
packet_put_int(min);
packet_put_int(nbits);
packet_put_int(max);
}
#ifdef DEBUG_KEXDH
fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
min, nbits, max);
#endif
packet_send();
debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
if ((p = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(p, &dlen);
if ((g = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(g, &dlen);
packet_done();
if (BN_num_bits(p) < min || BN_num_bits(p) > max)
fatal("DH_GEX group out of range: %d !< %d !< %d",
min, BN_num_bits(p), max);
dh = dh_new_group(g, p);
dh_gen_key(dh, kex->we_need * 8);
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
/* generate and send 'e', client DH public key */
packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
packet_put_bignum2(dh->pub_key);
packet_send();
debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
/* key, cert */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (kex->check_host_key == NULL)
fatal("cannot check server_host_key");
kex->check_host_key(server_host_key);
/* DH paramter f, server public DH key */
dh_server_pub = BN_new();
if (dh_server_pub == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
BN_print_fp(stderr, dh_server_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
/* signed H */
signature = packet_get_string(&slen);
packet_done();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_server_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
if (datafellows & SSH_OLD_DHGEX)
min = max = -1;
/* calc and verify H */
hash = kexgex_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
server_host_key_blob, sbloblen,
min, nbits, max,
dh->p, dh->g,
dh->pub_key,
dh_server_pub,
shared_secret
);
/* have keys, free DH */
DH_free(dh);
xfree(server_host_key_blob);
BN_free(dh_server_pub);
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
xfree(signature);
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
/* server */
void
kexgex_server(Kex *kex)
{
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
Key *server_host_key;
DH *dh = dh;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, kout;
int min = -1, max = -1, nbits = -1, type, plen, dlen, slen;
if (kex->load_host_key == NULL)
fatal("Cannot load hostkey");
server_host_key = kex->load_host_key(kex->hostkey_type);
if (server_host_key == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
type = packet_read(&plen);
switch(type){
case SSH2_MSG_KEX_DH_GEX_REQUEST:
debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
min = packet_get_int();
nbits = packet_get_int();
max = packet_get_int();
min = MAX(DH_GRP_MIN, min);
max = MIN(DH_GRP_MAX, max);
break;
case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
nbits = packet_get_int();
min = DH_GRP_MIN;
max = DH_GRP_MAX;
/* unused for old GEX */
break;
default:
fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
}
packet_done();
if (max < min || nbits < min || max < nbits)
fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
min, nbits, max);
dh = choose_dh(min, nbits, max);
if (dh == NULL)
packet_disconnect("Protocol error: no matching DH grp found");
debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
packet_put_bignum2(dh->p);
packet_put_bignum2(dh->g);
packet_send();
/* flush */
packet_write_wait();
/* Compute our exchange value in parallel with the client */
dh_gen_key(dh, kex->we_need * 8);
debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_INIT);
/* key, cert */
dh_client_pub = BN_new();
if (dh_client_pub == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
BN_print_fp(stderr, dh_client_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_client_pub));
#endif
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
fprintf(stderr, "\n");
#endif
if (!dh_pub_is_valid(dh, dh_client_pub))
packet_disconnect("bad client public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_client_pub, dh);
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
shared_secret = BN_new();
BN_bin2bn(kbuf, kout, shared_secret);
memset(kbuf, 0, klen);
xfree(kbuf);
key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
min = max = -1;
/* calc H */ /* XXX depends on 'kex' */
hash = kexgex_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
(char *)server_host_key_blob, sbloblen,
min, nbits, max,
dh->p, dh->g,
dh_client_pub,
dh->pub_key,
shared_secret
);
BN_free(dh_client_pub);
/* save session id := H */
/* XXX hashlen depends on KEX */
if (kex->session_id == NULL) {
kex->session_id_len = 20;
kex->session_id = xmalloc(kex->session_id_len);
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
/* XXX hashlen depends on KEX */
key_sign(server_host_key, &signature, &slen, hash, 20);
/* destroy_sensitive_data(); */
/* send server hostkey, DH pubkey 'f' and singed H */
debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
packet_put_string((char *)server_host_key_blob, sbloblen);
packet_put_bignum2(dh->pub_key); /* f */
packet_put_string((char *)signature, slen);
packet_send();
xfree(signature);
xfree(server_host_key_blob);
/* have keys, free DH */
DH_free(dh);
kex_derive_keys(kex, hash, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
void
kexgex(Kex *kex)
{
if (kex->server)
kexgex_server(kex);
else
kexgex_client(kex);
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: key.h,v 1.12 2001/04/17 10:53:24 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -24,11 +26,23 @@
#ifndef KEY_H
#define KEY_H
#include <openssl/rsa.h>
#include <openssl/dsa.h>
typedef struct Key Key;
enum types {
KEY_RSA1,
KEY_RSA,
KEY_DSA,
KEY_EMPTY
KEY_UNSPEC
};
enum fp_type {
SSH_FP_SHA1,
SSH_FP_MD5
};
enum fp_rep {
SSH_FP_HEX,
SSH_FP_BUBBLEBABBLE
};
struct Key {
int type;
@ -37,12 +51,34 @@ struct Key {
};
Key *key_new(int type);
Key *key_new_private(int type);
void key_free(Key *k);
int key_equal(Key *a, Key *b);
char *key_fingerprint(Key *k);
char *key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep);
char *key_type(Key *k);
int key_write(Key *key, FILE *f);
unsigned int key_read(Key *key, char **cpp);
unsigned int key_size(Key *k);
int key_read(Key *key, char **cpp);
u_int key_size(Key *k);
Key *key_generate(int type, u_int bits);
Key *key_from_private(Key *k);
int key_type_from_name(char *name);
Key *key_from_blob(char *blob, int blen);
int key_to_blob(Key *key, u_char **blobp, u_int *lenp);
char *key_ssh_name(Key *k);
int key_names_valid2(const char *names);
int
key_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen);
int
key_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen);
#endif

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.22 2001/04/03 19:53:30 markus Exp $
.PATH: ${.CURDIR}/..
LIB= ssh
@ -5,8 +7,8 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
cipher.c compat.c compress.c crc32.c deattack.c \
hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \
rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c \
cli.c rijndael.c
key.c dispatch.c kex.c mac.c uuencode.c misc.c \
cli.c rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c
NOPROFILE= yes
NOPIC= yes

View File

@ -10,8 +10,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Shared versions of debug(), log(), etc.
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,11 +34,78 @@
*/
#include "includes.h"
RCSID("$OpenBSD: log.c,v 1.11 2000/09/30 16:27:43 markus Exp $");
RCSID("$OpenBSD: log.c,v 1.17 2001/03/04 17:42:28 millert Exp $");
#include "ssh.h"
#include "log.h"
#include "xmalloc.h"
#include <syslog.h>
static LogLevel log_level = SYSLOG_LEVEL_INFO;
static int log_on_stderr = 1;
static int log_facility = LOG_AUTH;
static char *argv0;
extern char *__progname;
/* textual representation of log-facilities/levels */
static struct {
const char *name;
SyslogFacility val;
} log_facilities[] = {
{ "DAEMON", SYSLOG_FACILITY_DAEMON },
{ "USER", SYSLOG_FACILITY_USER },
{ "AUTH", SYSLOG_FACILITY_AUTH },
{ "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
{ "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
{ "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
{ "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
{ "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
{ NULL, 0 }
};
static struct {
const char *name;
LogLevel val;
} log_levels[] =
{
{ "QUIET", SYSLOG_LEVEL_QUIET },
{ "FATAL", SYSLOG_LEVEL_FATAL },
{ "ERROR", SYSLOG_LEVEL_ERROR },
{ "INFO", SYSLOG_LEVEL_INFO },
{ "VERBOSE", SYSLOG_LEVEL_VERBOSE },
{ "DEBUG", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
{ NULL, 0 }
};
SyslogFacility
log_facility_number(char *name)
{
int i;
if (name != NULL)
for (i = 0; log_facilities[i].name; i++)
if (strcasecmp(log_facilities[i].name, name) == 0)
return log_facilities[i].val;
return (SyslogFacility) - 1;
}
LogLevel
log_level_number(char *name)
{
int i;
if (name != NULL)
for (i = 0; log_levels[i].name; i++)
if (strcasecmp(log_levels[i].name, name) == 0)
return log_levels[i].val;
return (LogLevel) - 1;
}
/* Fatal messages. This function never returns. */
void
@ -154,8 +219,8 @@ fatal_remove_cleanup(void (*proc) (void *context), void *context)
return;
}
}
fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
(unsigned long) proc, (unsigned long) context);
fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx",
(u_long) proc, (u_long) context);
}
/* Cleanup and exit */
@ -172,67 +237,143 @@ fatal_cleanup(void)
for (cu = fatal_cleanups; cu; cu = next_cu) {
next_cu = cu->next;
debug("Calling cleanup 0x%lx(0x%lx)",
(unsigned long) cu->proc, (unsigned long) cu->context);
(u_long) cu->proc, (u_long) cu->context);
(*cu->proc) (cu->context);
}
exit(255);
}
/* textual representation of log-facilities/levels */
static struct {
const char *name;
SyslogFacility val;
} log_facilities[] = {
{ "DAEMON", SYSLOG_FACILITY_DAEMON },
{ "USER", SYSLOG_FACILITY_USER },
{ "AUTH", SYSLOG_FACILITY_AUTH },
{ "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
{ "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
{ "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
{ "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
{ "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
{ NULL, 0 }
};
/*
* Initialize the log.
*/
static struct {
const char *name;
LogLevel val;
} log_levels[] =
void
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
{
{ "QUIET", SYSLOG_LEVEL_QUIET },
{ "FATAL", SYSLOG_LEVEL_FATAL },
{ "ERROR", SYSLOG_LEVEL_ERROR },
{ "INFO", SYSLOG_LEVEL_INFO },
{ "VERBOSE", SYSLOG_LEVEL_VERBOSE },
{ "DEBUG", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
{ NULL, 0 }
};
argv0 = av0;
SyslogFacility
log_facility_number(char *name)
{
int i;
if (name != NULL)
for (i = 0; log_facilities[i].name; i++)
if (strcasecmp(log_facilities[i].name, name) == 0)
return log_facilities[i].val;
return (SyslogFacility) - 1;
switch (level) {
case SYSLOG_LEVEL_QUIET:
case SYSLOG_LEVEL_FATAL:
case SYSLOG_LEVEL_ERROR:
case SYSLOG_LEVEL_INFO:
case SYSLOG_LEVEL_VERBOSE:
case SYSLOG_LEVEL_DEBUG1:
case SYSLOG_LEVEL_DEBUG2:
case SYSLOG_LEVEL_DEBUG3:
log_level = level;
break;
default:
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
(int) level);
exit(1);
}
log_on_stderr = on_stderr;
if (on_stderr)
return;
switch (facility) {
case SYSLOG_FACILITY_DAEMON:
log_facility = LOG_DAEMON;
break;
case SYSLOG_FACILITY_USER:
log_facility = LOG_USER;
break;
case SYSLOG_FACILITY_AUTH:
log_facility = LOG_AUTH;
break;
case SYSLOG_FACILITY_LOCAL0:
log_facility = LOG_LOCAL0;
break;
case SYSLOG_FACILITY_LOCAL1:
log_facility = LOG_LOCAL1;
break;
case SYSLOG_FACILITY_LOCAL2:
log_facility = LOG_LOCAL2;
break;
case SYSLOG_FACILITY_LOCAL3:
log_facility = LOG_LOCAL3;
break;
case SYSLOG_FACILITY_LOCAL4:
log_facility = LOG_LOCAL4;
break;
case SYSLOG_FACILITY_LOCAL5:
log_facility = LOG_LOCAL5;
break;
case SYSLOG_FACILITY_LOCAL6:
log_facility = LOG_LOCAL6;
break;
case SYSLOG_FACILITY_LOCAL7:
log_facility = LOG_LOCAL7;
break;
default:
fprintf(stderr,
"Unrecognized internal syslog facility code %d\n",
(int) facility);
exit(1);
}
}
LogLevel
log_level_number(char *name)
#define MSGBUFSIZ 1024
void
do_log(LogLevel level, const char *fmt, va_list args)
{
int i;
if (name != NULL)
for (i = 0; log_levels[i].name; i++)
if (strcasecmp(log_levels[i].name, name) == 0)
return log_levels[i].val;
return (LogLevel) - 1;
char msgbuf[MSGBUFSIZ];
char fmtbuf[MSGBUFSIZ];
char *txt = NULL;
int pri = LOG_INFO;
if (level > log_level)
return;
switch (level) {
case SYSLOG_LEVEL_FATAL:
if (!log_on_stderr)
txt = "fatal";
pri = LOG_CRIT;
break;
case SYSLOG_LEVEL_ERROR:
if (!log_on_stderr)
txt = "error";
pri = LOG_ERR;
break;
case SYSLOG_LEVEL_INFO:
pri = LOG_INFO;
break;
case SYSLOG_LEVEL_VERBOSE:
pri = LOG_INFO;
break;
case SYSLOG_LEVEL_DEBUG1:
txt = "debug1";
pri = LOG_DEBUG;
break;
case SYSLOG_LEVEL_DEBUG2:
txt = "debug2";
pri = LOG_DEBUG;
break;
case SYSLOG_LEVEL_DEBUG3:
txt = "debug3";
pri = LOG_DEBUG;
break;
default:
txt = "internal error";
pri = LOG_ERR;
break;
}
if (txt != NULL) {
snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
} else {
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
}
if (log_on_stderr) {
fprintf(stderr, "%s\r\n", msgbuf);
} else {
openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
syslog(pri, "%.500s", msgbuf);
closelog();
}
}

75
crypto/openssh/log.h Normal file
View File

@ -0,0 +1,75 @@
/* $OpenBSD: log.h,v 1.2 2001/01/29 01:58:16 niklas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef SSH_LOG_H
#define SSH_LOG_H
/* Supported syslog facilities and levels. */
typedef enum {
SYSLOG_FACILITY_DAEMON,
SYSLOG_FACILITY_USER,
SYSLOG_FACILITY_AUTH,
SYSLOG_FACILITY_LOCAL0,
SYSLOG_FACILITY_LOCAL1,
SYSLOG_FACILITY_LOCAL2,
SYSLOG_FACILITY_LOCAL3,
SYSLOG_FACILITY_LOCAL4,
SYSLOG_FACILITY_LOCAL5,
SYSLOG_FACILITY_LOCAL6,
SYSLOG_FACILITY_LOCAL7
} SyslogFacility;
typedef enum {
SYSLOG_LEVEL_QUIET,
SYSLOG_LEVEL_FATAL,
SYSLOG_LEVEL_ERROR,
SYSLOG_LEVEL_INFO,
SYSLOG_LEVEL_VERBOSE,
SYSLOG_LEVEL_DEBUG1,
SYSLOG_LEVEL_DEBUG2,
SYSLOG_LEVEL_DEBUG3
} LogLevel;
/* Initializes logging. */
void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
/* Logging implementation, depending on server or client */
void do_log(LogLevel level, const char *fmt, va_list args);
/* name to facility/level */
SyslogFacility log_facility_number(char *name);
LogLevel log_level_number(char *name);
/* Output a message to syslog or stderr */
void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void error(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void log(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug2(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug3(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/* same as fatal() but w/o logging */
void fatal_cleanup(void);
/*
* Registers a cleanup function to be called by fatal()/fatal_cleanup()
* before exiting. It is permissible to call fatal_remove_cleanup for the
* function itself from the function.
*/
void fatal_add_cleanup(void (*proc) (void *context), void *context);
/* Removes a cleanup function to be called at fatal(). */
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
#endif

114
crypto/openssh/mac.c Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: mac.c,v 1.2 2001/04/05 10:42:51 markus Exp $");
#include <openssl/hmac.h>
#include "xmalloc.h"
#include "getput.h"
#include "log.h"
#include "cipher.h"
#include "kex.h"
#include "mac.h"
struct {
char *name;
EVP_MD * (*mdfunc)(void);
int truncatebits; /* truncate digest if != 0 */
} macs[] = {
{ "hmac-sha1", EVP_sha1, 0, },
{ "hmac-sha1-96", EVP_sha1, 96 },
{ "hmac-md5", EVP_md5, 0 },
{ "hmac-md5-96", EVP_md5, 96 },
{ "hmac-ripemd160", EVP_ripemd160, 0 },
{ "hmac-ripemd160@openssh.com", EVP_ripemd160, 0 },
{ NULL, NULL, 0 }
};
int
mac_init(Mac *mac, char *name)
{
int i;
for (i = 0; macs[i].name; i++) {
if (strcmp(name, macs[i].name) == 0) {
if (mac != NULL) {
mac->md = (*macs[i].mdfunc)();
mac->key_len = mac->mac_len = mac->md->md_size;
if (macs[i].truncatebits != 0)
mac->mac_len = macs[i].truncatebits/8;
}
debug2("mac_init: found %s", name);
return (0);
}
}
debug2("mac_init: unknown %s", name);
return (-1);
}
u_char *
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
{
HMAC_CTX c;
static u_char m[EVP_MAX_MD_SIZE];
u_char b[4];
if (mac->key == NULL)
fatal("mac_compute: no key");
if (mac->mac_len > sizeof(m))
fatal("mac_compute: mac too long");
HMAC_Init(&c, mac->key, mac->key_len, mac->md);
PUT_32BIT(b, seqno);
HMAC_Update(&c, b, sizeof(b));
HMAC_Update(&c, data, datalen);
HMAC_Final(&c, m, NULL);
HMAC_cleanup(&c);
return (m);
}
/* XXX copied from ciphers_valid */
#define MAC_SEP ","
int
mac_valid(const char *names)
{
char *maclist, *cp, *p;
if (names == NULL || strcmp(names, "") == 0)
return (0);
maclist = cp = xstrdup(names);
for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
(p = strsep(&cp, MAC_SEP))) {
if (mac_init(NULL, p) < 0) {
debug("bad mac %s [%s]", p, names);
xfree(maclist);
return (0);
} else {
debug3("mac ok: %s [%s]", p, names);
}
}
debug3("macs ok: [%s]", names);
xfree(maclist);
return (1);
}

28
crypto/openssh/mac.h Normal file
View File

@ -0,0 +1,28 @@
/* $OpenBSD: mac.h,v 1.1 2001/02/11 12:59:24 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
int mac_valid(const char *names);
int mac_init(Mac *mac, char *name);
u_char *mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen);

View File

@ -10,11 +10,35 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: match.c,v 1.9 2000/09/07 20:27:52 deraadt Exp $");
RCSID("$OpenBSD: match.c,v 1.12 2001/03/10 17:51:04 markus Exp $");
#include "ssh.h"
#include "match.h"
#include "xmalloc.h"
/*
* Returns true if the given string matches the pattern (which may contain ?
@ -87,12 +111,12 @@ match_pattern(const char *s, const char *pattern)
*/
int
match_hostname(const char *host, const char *pattern, unsigned int len)
match_hostname(const char *host, const char *pattern, u_int len)
{
char sub[1024];
int negated;
int got_positive;
unsigned int i, subi;
u_int i, subi;
got_positive = 0;
for (i = 0; i < len;) {
@ -137,3 +161,46 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
*/
return got_positive;
}
#define MAX_PROP 20
#define SEP ","
char *
match_list(const char *client, const char *server, u_int *next)
{
char *sproposals[MAX_PROP];
char *c, *s, *p, *ret, *cp, *sp;
int i, j, nproposals;
c = cp = xstrdup(client);
s = sp = xstrdup(server);
for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
(p = strsep(&sp, SEP)), i++) {
if (i < MAX_PROP)
sproposals[i] = p;
else
break;
}
nproposals = i;
for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
(p = strsep(&cp, SEP)), i++) {
for (j = 0; j < nproposals; j++) {
if (strcmp(p, sproposals[j]) == 0) {
ret = xstrdup(p);
if (next != NULL)
*next = (cp == NULL) ?
strlen(c) : cp - c;
xfree(c);
xfree(s);
return ret;
}
}
}
if (next != NULL)
*next = strlen(c);
xfree(c);
xfree(s);
return NULL;
}

View File

@ -1,3 +1,5 @@
/* $OpenBSD: match.h,v 1.7 2001/03/10 17:51:04 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -26,6 +28,12 @@ int match_pattern(const char *s, const char *pattern);
* indicate negation). Returns -1 if negation matches, 1 if there is
* a positive match, 0 if there is no match at all.
*/
int match_hostname(const char *host, const char *pattern, unsigned int len);
int match_hostname(const char *host, const char *pattern, u_int len);
/*
* Returns first item from client-list that is also supported by server-list,
* caller must xfree() returned string.
*/
char *match_list(const char *client, const char *server, u_int *next);
#endif

130
crypto/openssh/misc.c Normal file
View File

@ -0,0 +1,130 @@
/* $OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: misc.c,v 1.5 2001/04/12 20:09:37 stevesk Exp $");
#include "misc.h"
#include "log.h"
#include "xmalloc.h"
char *
chop(char *s)
{
char *t = s;
while (*t) {
if(*t == '\n' || *t == '\r') {
*t = '\0';
return s;
}
t++;
}
return s;
}
void
set_nonblock(int fd)
{
int val;
val = fcntl(fd, F_GETFL, 0);
if (val < 0) {
error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
return;
}
if (val & O_NONBLOCK) {
debug("fd %d IS O_NONBLOCK", fd);
return;
}
debug("fd %d setting O_NONBLOCK", fd);
val |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, val) == -1)
if (errno != ENODEV)
error("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
fd, strerror(errno));
}
/* Characters considered whitespace in strsep calls. */
#define WHITESPACE " \t\r\n"
char *
strdelim(char **s)
{
char *old;
int wspace = 0;
if (*s == NULL)
return NULL;
old = *s;
*s = strpbrk(*s, WHITESPACE "=");
if (*s == NULL)
return (old);
/* Allow only one '=' to be skipped */
if (*s[0] == '=')
wspace = 1;
*s[0] = '\0';
*s += strspn(*s + 1, WHITESPACE) + 1;
if (*s[0] == '=' && !wspace)
*s += strspn(*s + 1, WHITESPACE) + 1;
return (old);
}
struct passwd *
pwcopy(struct passwd *pw)
{
struct passwd *copy = xmalloc(sizeof(*copy));
memset(copy, 0, sizeof(*copy));
copy->pw_name = xstrdup(pw->pw_name);
copy->pw_passwd = xstrdup(pw->pw_passwd);
copy->pw_gecos = xstrdup(pw->pw_gecos);
copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid;
copy->pw_class = xstrdup(pw->pw_class);
copy->pw_dir = xstrdup(pw->pw_dir);
copy->pw_shell = xstrdup(pw->pw_shell);
return copy;
}
int a2port(const char *s)
{
long port;
char *endp;
errno = 0;
port = strtol(s, &endp, 0);
if (s == endp || *endp != '\0' ||
(errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
port <= 0 || port > 65535)
return 0;
return port;
}

30
crypto/openssh/misc.h Normal file
View File

@ -0,0 +1,30 @@
/* $OpenBSD: misc.h,v 1.4 2001/04/12 20:09:36 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/* remove newline at end of string */
char *chop(char *s);
/* return next token in configuration line */
char *strdelim(char **s);
/* set filedescriptor to non-blocking */
void set_nonblock(int fd);
struct passwd * pwcopy(struct passwd *pw);
/*
* Convert ASCII string to TCP/IP port number.
* Port must be >0 and <=65535.
* Return 0 if invalid.
*/
int a2port(const char *s);

View File

@ -12,7 +12,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: mpaux.h,v 1.8 2000/09/07 20:27:52 deraadt Exp $"); */
/* RCSID("$OpenBSD: mpaux.h,v 1.9 2000/12/19 23:17:57 markus Exp $"); */
#ifndef MPAUX_H
#define MPAUX_H
@ -23,8 +23,8 @@
* representations of host_key_n, session_key_n, and the cookie.
*/
void
compute_session_id(unsigned char session_id[16],
unsigned char cookie[8],
compute_session_id(u_char session_id[16],
u_char cookie[8],
BIGNUM * host_key_n,
BIGNUM * session_key_n);

View File

@ -1,3 +1,5 @@
/* $OpenBSD: myproposal.h,v 1.12 2001/03/05 15:56:16 deraadt Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -22,13 +24,16 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1"
#define KEX_DEFAULT_PK_ALG "ssh-dss"
#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss"
#define KEX_DEFAULT_ENCRYPT \
"3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \
"aes128-cbc,aes192-cbc,aes256-cbc," \
"aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \
"aes192-cbc,aes256-cbc," \
"rijndael128-cbc,rijndael192-cbc,rijndael256-cbc," \
"rijndael-cbc@lysator.liu.se"
#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com"
#define KEX_DEFAULT_MAC \
"hmac-md5,hmac-sha1,hmac-ripemd160," \
"hmac-ripemd160@openssh.com," \
"hmac-sha1-96,hmac-md5-96"
#define KEX_DEFAULT_COMP "none,zlib"
#define KEX_DEFAULT_LANG ""

View File

@ -23,17 +23,16 @@
*/
#include "includes.h"
RCSID("$OpenBSD: nchan.c,v 1.19 2000/09/07 20:27:52 deraadt Exp $");
#include "ssh.h"
RCSID("$OpenBSD: nchan.c,v 1.23 2001/02/28 08:54:55 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
#include "buffer.h"
#include "packet.h"
#include "channels.h"
#include "nchan.h"
#include "ssh2.h"
#include "compat.h"
#include "log.h"
/* functions manipulating channel states */
/*
@ -55,9 +54,6 @@ static void chan_send_oclose1(Channel *c);
static void chan_send_close2(Channel *c);
static void chan_send_eof2(Channel *c);
/* channel cleanup */
chan_event_fn *chan_delete_if_full_closed = NULL;
/* helper */
static void chan_shutdown_write(Channel *c);
static void chan_shutdown_read(Channel *c);
@ -250,14 +246,6 @@ chan_send_oclose1(Channel *c)
break;
}
}
static void
chan_delete_if_full_closed1(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
debug("channel %d: full closed", c->self);
channel_free(c->self);
}
}
/*
* the same for SSH2
@ -400,22 +388,46 @@ chan_send_close2(Channel *c)
c->flags |= CHAN_CLOSE_SENT;
}
}
static void
chan_delete_if_full_closed2(Channel *c)
/* shared */
int
chan_is_dead(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
return 0;
if (!compat20) {
debug("channel %d: is dead", c->self);
return 1;
}
/*
* we have to delay the close message if the efd (for stderr) is
* still active
*/
if (((c->extended_usage != CHAN_EXTENDED_IGNORE) &&
buffer_len(&c->extended) > 0)
#if 0
|| ((c->extended_usage == CHAN_EXTENDED_READ) &&
c->efd != -1)
#endif
) {
debug2("channel %d: active efd: %d len %d type %s",
c->self, c->efd, buffer_len(&c->extended),
c->extended_usage==CHAN_EXTENDED_READ ?
"read": "write");
} else {
if (!(c->flags & CHAN_CLOSE_SENT)) {
chan_send_close2(c);
}
if ((c->flags & CHAN_CLOSE_SENT) &&
(c->flags & CHAN_CLOSE_RCVD)) {
debug("channel %d: full closed2", c->self);
channel_free(c->self);
debug("channel %d: is dead", c->self);
return 1;
}
}
return 0;
}
/* shared */
void
chan_init_iostates(Channel *c)
{
@ -436,8 +448,6 @@ chan_init(void)
chan_rcvd_ieof = chan_rcvd_ieof2;
chan_write_failed = chan_write_failed2;
chan_obuf_empty = chan_obuf_empty2;
chan_delete_if_full_closed = chan_delete_if_full_closed2;
} else {
chan_rcvd_oclose = chan_rcvd_oclose1;
chan_read_failed = chan_read_failed_12;
@ -446,8 +456,6 @@ chan_init(void)
chan_rcvd_ieof = chan_rcvd_ieof1;
chan_write_failed = chan_write_failed1;
chan_obuf_empty = chan_obuf_empty1;
chan_delete_if_full_closed = chan_delete_if_full_closed1;
}
}

View File

@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: nchan.h,v 1.9 2000/09/07 20:27:52 deraadt Exp $"); */
/* RCSID("$OpenBSD: nchan.h,v 1.10 2001/02/28 08:54:55 markus Exp $"); */
#ifndef NCHAN_H
#define NCHAN_H
@ -84,7 +84,7 @@ extern chan_event_fn *chan_rcvd_ieof;
extern chan_event_fn *chan_write_failed;
extern chan_event_fn *chan_obuf_empty;
extern chan_event_fn *chan_delete_if_full_closed;
int chan_is_dead(Channel * c);
void chan_init_iostates(Channel * c);
void chan_init(void);

View File

@ -1,3 +1,5 @@
.\" $OpenBSD: nchan.ms,v 1.7 2001/01/29 01:58:17 niklas Exp $
.\"
.\"
.\" Copyright (c) 1999 Markus Friedl. All rights reserved.
.\"

View File

@ -37,13 +37,12 @@
*/
#include "includes.h"
RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $");
RCSID("$OpenBSD: packet.c,v 1.61 2001/04/05 10:42:51 markus Exp $");
#include "xmalloc.h"
#include "buffer.h"
#include "packet.h"
#include "bufaux.h"
#include "ssh.h"
#include "crc32.h"
#include "getput.h"
@ -52,15 +51,14 @@ RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $");
#include "channels.h"
#include "compat.h"
#include "ssh1.h"
#include "ssh2.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include "buffer.h"
#include "cipher.h"
#include "kex.h"
#include "hmac.h"
#include "mac.h"
#include "log.h"
#include "canohost.h"
#ifdef PACKET_DEBUG
#define DBG(x) x
@ -84,7 +82,7 @@ static int connection_out = -1;
static int cipher_type = SSH_CIPHER_NONE;
/* Protocol flags for the remote side. */
static unsigned int remote_protocol_flags = 0;
static u_int remote_protocol_flags = 0;
/* Encryption context for receiving data. This is only used for decryption. */
static CipherContext receive_context;
@ -106,6 +104,7 @@ static Buffer incoming_packet;
/* Scratch buffer for packet compression/decompression. */
static Buffer compression_buffer;
static int compression_buffer_ready = 0;
/* Flag indicating whether packet compression/decompression is enabled. */
static int packet_compression = 0;
@ -123,35 +122,14 @@ static int interactive_mode = 0;
int use_ssh2_packet_format = 0;
/* Session key information for Encryption and MAC */
Kex *kex = NULL;
Newkeys *newkeys[MODE_MAX];
void
packet_set_kex(Kex *k)
{
if( k->mac[MODE_IN ].key == NULL ||
k->enc[MODE_IN ].key == NULL ||
k->enc[MODE_IN ].iv == NULL ||
k->mac[MODE_OUT].key == NULL ||
k->enc[MODE_OUT].key == NULL ||
k->enc[MODE_OUT].iv == NULL)
fatal("bad KEX");
kex = k;
}
void
clear_enc_keys(Enc *enc, int len)
{
memset(enc->iv, 0, len);
memset(enc->key, 0, len);
xfree(enc->iv);
xfree(enc->key);
enc->iv = NULL;
enc->key = NULL;
}
void
packet_set_ssh2_format(void)
{
DBG(debug("use_ssh2_packet_format"));
use_ssh2_packet_format = 1;
newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
}
/*
@ -167,8 +145,8 @@ packet_set_connection(int fd_in, int fd_out)
connection_in = fd_in;
connection_out = fd_out;
cipher_type = SSH_CIPHER_NONE;
cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0);
cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0);
cipher_init(&send_context, none, (u_char *) "", 0, NULL, 0);
cipher_init(&receive_context, none, (u_char *) "", 0, NULL, 0);
if (!initialized) {
initialized = 1;
buffer_init(&input);
@ -272,7 +250,7 @@ packet_close()
buffer_free(&output);
buffer_free(&outgoing_packet);
buffer_free(&incoming_packet);
if (packet_compression) {
if (compression_buffer_ready) {
buffer_free(&compression_buffer);
buffer_compress_uninit();
}
@ -281,7 +259,7 @@ packet_close()
/* Sets remote side protocol flags. */
void
packet_set_protocol_flags(unsigned int protocol_flags)
packet_set_protocol_flags(u_int protocol_flags)
{
remote_protocol_flags = protocol_flags;
channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0);
@ -289,7 +267,7 @@ packet_set_protocol_flags(unsigned int protocol_flags)
/* Returns the remote protocol flags set earlier by the above function. */
unsigned int
u_int
packet_get_protocol_flags()
{
return remote_protocol_flags;
@ -300,15 +278,24 @@ packet_get_protocol_flags()
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
*/
/*** XXXXX todo: kex means re-init */
void
packet_init_compression()
{
if (compression_buffer_ready == 1)
return;
compression_buffer_ready = 1;
buffer_init(&compression_buffer);
}
void
packet_start_compression(int level)
{
if (packet_compression)
if (packet_compression && !use_ssh2_packet_format)
fatal("Compression already enabled.");
packet_compression = 1;
buffer_init(&compression_buffer);
buffer_compress_init(level);
packet_init_compression();
buffer_compress_init_send(level);
buffer_compress_init_recv();
}
/*
@ -318,7 +305,7 @@ packet_start_compression(int level)
void
packet_encrypt(CipherContext * cc, void *dest, void *src,
unsigned int bytes)
u_int bytes)
{
cipher_encrypt(cc, dest, src, bytes);
}
@ -329,7 +316,7 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
*/
void
packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes)
packet_decrypt(CipherContext *context, void *dest, void *src, u_int bytes)
{
/*
* Cryptographic attack detector for ssh - Modifications for packet.c
@ -350,7 +337,7 @@ packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes
*/
void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
packet_set_encryption_key(const u_char *key, u_int keylen,
int number)
{
Cipher *cipher = cipher_by_number(number);
@ -391,7 +378,7 @@ packet_start2(int type)
void
packet_start(int type)
{
DBG(debug("packet_start[%d]",type));
DBG(debug("packet_start[%d]", type));
if (use_ssh2_packet_format)
packet_start2(type);
else
@ -410,7 +397,7 @@ packet_put_char(int value)
/* Appends an integer to the packet data. */
void
packet_put_int(unsigned int value)
packet_put_int(u_int value)
{
buffer_put_int(&outgoing_packet, value);
}
@ -418,7 +405,7 @@ packet_put_int(unsigned int value)
/* Appends a string to packet data. */
void
packet_put_string(const char *buf, unsigned int len)
packet_put_string(const char *buf, u_int len)
{
buffer_put_string(&outgoing_packet, buf, len);
}
@ -429,7 +416,7 @@ packet_put_cstring(const char *str)
}
void
packet_put_raw(const char *buf, unsigned int len)
packet_put_raw(const char *buf, u_int len)
{
buffer_append(&outgoing_packet, buf, len);
}
@ -454,11 +441,11 @@ packet_put_bignum2(BIGNUM * value)
*/
void
packet_send1()
packet_send1(void)
{
char buf[8], *cp;
int i, padding, len;
unsigned int checksum;
u_int checksum;
u_int32_t rand = 0;
/*
@ -493,7 +480,7 @@ packet_send1()
buffer_consume(&outgoing_packet, 8 - padding);
/* Add check bytes. */
checksum = ssh_crc32((unsigned char *) buffer_ptr(&outgoing_packet),
checksum = ssh_crc32((u_char *) buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
PUT_32BIT(buf, checksum);
buffer_append(&outgoing_packet, buf, 4);
@ -524,28 +511,78 @@ packet_send1()
*/
}
void
set_newkeys(int mode)
{
Enc *enc;
Mac *mac;
Comp *comp;
CipherContext *cc;
debug("newkeys: mode %d", mode);
cc = (mode == MODE_OUT) ? &send_context : &receive_context;
if (newkeys[mode] != NULL) {
debug("newkeys: rekeying");
/* todo: free old keys, reset compression/cipher-ctxt; */
memset(cc, 0, sizeof(*cc));
enc = &newkeys[mode]->enc;
mac = &newkeys[mode]->mac;
comp = &newkeys[mode]->comp;
memset(mac->key, 0, mac->key_len);
xfree(enc->name);
xfree(enc->iv);
xfree(enc->key);
xfree(mac->name);
xfree(mac->key);
xfree(comp->name);
xfree(newkeys[mode]);
}
newkeys[mode] = kex_get_newkeys(mode);
if (newkeys[mode] == NULL)
fatal("newkeys: no keys for mode %d", mode);
enc = &newkeys[mode]->enc;
mac = &newkeys[mode]->mac;
comp = &newkeys[mode]->comp;
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_init_context: %d", mode));
cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len,
enc->iv, enc->cipher->block_size);
memset(enc->iv, 0, enc->cipher->block_size);
memset(enc->key, 0, enc->cipher->key_len);
if (comp->type != 0 && comp->enabled == 0) {
packet_init_compression();
if (mode == MODE_OUT)
buffer_compress_init_send(6);
else
buffer_compress_init_recv();
comp->enabled = 1;
}
}
/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
void
packet_send2()
packet_send2(void)
{
unsigned char *macbuf = NULL;
static u_int32_t seqnr = 0;
u_char *macbuf = NULL;
char *cp;
unsigned int packet_length = 0;
unsigned int i, padlen, len;
u_int packet_length = 0;
u_int i, padlen, len;
u_int32_t rand = 0;
static unsigned int seqnr = 0;
int type;
Enc *enc = NULL;
Mac *mac = NULL;
Comp *comp = NULL;
int block_size;
if (kex != NULL) {
enc = &kex->enc[MODE_OUT];
mac = &kex->mac[MODE_OUT];
comp = &kex->comp[MODE_OUT];
if (newkeys[MODE_OUT] != NULL) {
enc = &newkeys[MODE_OUT]->enc;
mac = &newkeys[MODE_OUT]->mac;
comp = &newkeys[MODE_OUT]->comp;
}
block_size = enc ? enc->cipher->block_size : 8;
@ -588,7 +625,7 @@ packet_send2()
if (i % 4 == 0)
rand = arc4random();
cp[i] = rand & 0xff;
rand <<= 8;
rand >>= 8;
}
} else {
/* clear padding */
@ -603,11 +640,9 @@ packet_send2()
/* compute MAC over seqnr and packet(length fields, payload, padding) */
if (mac && mac->enabled) {
macbuf = hmac( mac->md, seqnr,
(unsigned char *) buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet),
mac->key, mac->key_len
);
macbuf = mac_compute(mac, seqnr,
(u_char *) buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
DBG(debug("done calc MAC out #%d", seqnr));
}
/* encrypt packet and append to output buffer. */
@ -626,22 +661,8 @@ packet_send2()
log("outgoing seqnr wraps around");
buffer_clear(&outgoing_packet);
if (type == SSH2_MSG_NEWKEYS) {
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
fatal("packet_send2: no KEX");
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_init send_context"));
cipher_init(&send_context, enc->cipher,
enc->key, enc->cipher->key_len,
enc->iv, enc->cipher->block_size);
clear_enc_keys(enc, kex->we_need);
if (comp->type != 0 && comp->enabled == 0) {
comp->enabled = 1;
if (! packet_compression)
packet_start_compression(6);
}
}
if (type == SSH2_MSG_NEWKEYS)
set_newkeys(MODE_OUT);
}
void
@ -664,10 +685,13 @@ int
packet_read(int *payload_len_ptr)
{
int type, len;
fd_set set;
fd_set *setp;
char buf[8192];
DBG(debug("packet_read()"));
setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
sizeof(fd_mask));
/* Since we are blocking, ensure that all written packets have been sent. */
packet_write_wait();
@ -682,17 +706,22 @@ packet_read(int *payload_len_ptr)
|| type == SSH_CMSG_EXIT_CONFIRMATION))
packet_integrity_check(*payload_len_ptr, 0, type);
/* If we got a packet, return it. */
if (type != SSH_MSG_NONE)
if (type != SSH_MSG_NONE) {
xfree(setp);
return type;
}
/*
* Otherwise, wait for some data to arrive, add it to the
* buffer, and try again.
*/
FD_ZERO(&set);
FD_SET(connection_in, &set);
memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
sizeof(fd_mask));
FD_SET(connection_in, setp);
/* Wait for some data to arrive. */
select(connection_in + 1, &set, NULL, NULL, NULL);
while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
(errno == EAGAIN || errno == EINTR))
;
/* Read data from the socket. */
len = read(connection_in, buf, sizeof(buf));
@ -742,16 +771,16 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
int
packet_read_poll1(int *payload_len_ptr)
{
unsigned int len, padded_len;
unsigned char *ucp;
u_int len, padded_len;
u_char *ucp;
char buf[8], *cp;
unsigned int checksum, stored_checksum;
u_int checksum, stored_checksum;
/* Check if input size is less than minimum packet size. */
if (buffer_len(&input) < 4 + 8)
return SSH_MSG_NONE;
/* Get length of incoming packet. */
ucp = (unsigned char *) buffer_ptr(&input);
ucp = (u_char *) buffer_ptr(&input);
len = GET_32BIT(ucp);
if (len < 1 + 2 + 2 || len > 256 * 1024)
packet_disconnect("Bad packet length %d.", len);
@ -778,7 +807,7 @@ packet_read_poll1(int *payload_len_ptr)
#endif
/* Compute packet checksum. */
checksum = ssh_crc32((unsigned char *) buffer_ptr(&incoming_packet),
checksum = ssh_crc32((u_char *) buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet) - 4);
/* Skip padding. */
@ -790,7 +819,7 @@ packet_read_poll1(int *payload_len_ptr)
packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
len, buffer_len(&incoming_packet));
ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4;
ucp = (u_char *) buffer_ptr(&incoming_packet) + len - 4;
stored_checksum = GET_32BIT(ucp);
if (checksum != stored_checksum)
packet_disconnect("Corrupted check bytes on input.");
@ -811,28 +840,28 @@ packet_read_poll1(int *payload_len_ptr)
*payload_len_ptr = buffer_len(&incoming_packet);
/* Return type. */
return (unsigned char) buf[0];
return (u_char) buf[0];
}
int
packet_read_poll2(int *payload_len_ptr)
{
unsigned int padlen, need;
unsigned char buf[8], *macbuf;
unsigned char *ucp;
static u_int32_t seqnr = 0;
static u_int packet_length = 0;
u_int padlen, need;
u_char buf[8], *macbuf;
u_char *ucp;
char *cp;
static unsigned int packet_length = 0;
static unsigned int seqnr = 0;
int type;
int maclen, block_size;
Enc *enc = NULL;
Mac *mac = NULL;
Comp *comp = NULL;
if (kex != NULL) {
enc = &kex->enc[MODE_IN];
mac = &kex->mac[MODE_IN];
comp = &kex->comp[MODE_IN];
if (newkeys[MODE_IN] != NULL) {
enc = &newkeys[MODE_IN]->enc;
mac = &newkeys[MODE_IN]->mac;
comp = &newkeys[MODE_IN]->comp;
}
maclen = mac && mac->enabled ? mac->mac_len : 0;
block_size = enc ? enc->cipher->block_size : 8;
@ -848,7 +877,7 @@ packet_read_poll2(int *payload_len_ptr)
buffer_append_space(&incoming_packet, &cp, block_size);
packet_decrypt(&receive_context, cp, buffer_ptr(&input),
block_size);
ucp = (unsigned char *) buffer_ptr(&incoming_packet);
ucp = (u_char *) buffer_ptr(&incoming_packet);
packet_length = GET_32BIT(ucp);
if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
buffer_dump(&incoming_packet);
@ -882,11 +911,9 @@ packet_read_poll2(int *payload_len_ptr)
* increment sequence number for incoming packet
*/
if (mac && mac->enabled) {
macbuf = hmac( mac->md, seqnr,
(unsigned char *) buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet),
mac->key, mac->key_len
);
macbuf = mac_compute(mac, seqnr,
(u_char *) buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet));
if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
packet_disconnect("Corrupted MAC on input.");
DBG(debug("MAC #%d ok", seqnr));
@ -926,30 +953,16 @@ packet_read_poll2(int *payload_len_ptr)
packet_length = 0;
/* extract packet type */
type = (unsigned char)buf[0];
type = (u_char)buf[0];
if (type == SSH2_MSG_NEWKEYS) {
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
fatal("packet_read_poll2: no KEX");
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_init receive_context"));
cipher_init(&receive_context, enc->cipher,
enc->key, enc->cipher->key_len,
enc->iv, enc->cipher->block_size);
clear_enc_keys(enc, kex->we_need);
if (comp->type != 0 && comp->enabled == 0) {
comp->enabled = 1;
if (! packet_compression)
packet_start_compression(6);
}
}
if (type == SSH2_MSG_NEWKEYS)
set_newkeys(MODE_IN);
#ifdef PACKET_DEBUG
fprintf(stderr, "read/plain[%d]:\r\n",type);
fprintf(stderr, "read/plain[%d]:\r\n", type);
buffer_dump(&incoming_packet);
#endif
return (unsigned char)type;
return (u_char)type;
}
int
@ -979,14 +992,15 @@ packet_read_poll(int *payload_len_ptr)
case SSH2_MSG_DISCONNECT:
reason = packet_get_int();
msg = packet_get_string(NULL);
log("Received disconnect: %d: %.900s", reason, msg);
log("Received disconnect from %s: %d: %.400s", get_remote_ipaddr(),
reason, msg);
xfree(msg);
fatal_cleanup();
break;
default:
return type;
break;
}
}
} else {
switch(type) {
case SSH_MSG_IGNORE:
@ -998,7 +1012,8 @@ packet_read_poll(int *payload_len_ptr)
break;
case SSH_MSG_DISCONNECT:
msg = packet_get_string(NULL);
log("Received disconnect: %.900s", msg);
log("Received disconnect from %s: %.400s", get_remote_ipaddr(),
msg);
fatal_cleanup();
xfree(msg);
break;
@ -1007,7 +1022,7 @@ packet_read_poll(int *payload_len_ptr)
DBG(debug("received packet type %d", type));
return type;
break;
}
}
}
}
}
@ -1018,24 +1033,24 @@ packet_read_poll(int *payload_len_ptr)
*/
void
packet_process_incoming(const char *buf, unsigned int len)
packet_process_incoming(const char *buf, u_int len)
{
buffer_append(&input, buf, len);
}
/* Returns a character from the packet. */
unsigned int
u_int
packet_get_char()
{
char ch;
buffer_get(&incoming_packet, &ch, 1);
return (unsigned char) ch;
return (u_char) ch;
}
/* Returns an integer from the packet data. */
unsigned int
u_int
packet_get_int()
{
return buffer_get_int(&incoming_packet);
@ -1081,7 +1096,7 @@ packet_remaining(void)
*/
char *
packet_get_string(unsigned int *length_ptr)
packet_get_string(u_int *length_ptr)
{
return buffer_get_string(&incoming_packet, length_ptr);
}
@ -1101,6 +1116,9 @@ packet_send_debug(const char *fmt,...)
char buf[1024];
va_list args;
if (compat20 && (datafellows & SSH_BUG_DEBUG))
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
@ -1193,14 +1211,21 @@ packet_write_poll()
void
packet_write_wait()
{
fd_set *setp;
setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
sizeof(fd_mask));
packet_write_poll();
while (packet_have_data_to_write()) {
fd_set set;
FD_ZERO(&set);
FD_SET(connection_out, &set);
select(connection_out + 1, NULL, &set, NULL, NULL);
memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
sizeof(fd_mask));
FD_SET(connection_out, setp);
while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
(errno == EAGAIN || errno == EINTR))
;
packet_write_poll();
}
xfree(setp);
}
/* Returns true if there is buffered data to write to the connection. */
@ -1225,45 +1250,45 @@ packet_not_very_much_data_to_write()
/* Informs that the current session is interactive. Sets IP flags for that. */
void
packet_set_interactive(int interactive, int keepalives)
packet_set_interactive(int interactive)
{
static int called = 0;
int lowdelay = IPTOS_LOWDELAY;
int throughput = IPTOS_THROUGHPUT;
int on = 1;
if (called)
return;
called = 1;
/* Record that we are in interactive mode. */
interactive_mode = interactive;
/* Only set socket options if using a socket. */
if (!packet_connection_is_on_socket())
return;
if (keepalives) {
/* Set keepalives if requested. */
if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *) &on,
sizeof(on)) < 0)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
}
/*
* IPTOS_LOWDELAY, TCP_NODELAY and IPTOS_THROUGHPUT are IPv4 only
* IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
*/
if (!packet_connection_is_ipv4())
return;
if (interactive) {
/*
* Set IP options for an interactive connection. Use
* IPTOS_LOWDELAY and TCP_NODELAY.
*/
int lowdelay = IPTOS_LOWDELAY;
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
sizeof(lowdelay)) < 0)
error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno));
if (packet_connection_is_ipv4()) {
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
(void *) &lowdelay, sizeof(lowdelay)) < 0)
error("setsockopt IPTOS_LOWDELAY: %.100s",
strerror(errno));
}
if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on,
sizeof(on)) < 0)
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
} else {
} else if (packet_connection_is_ipv4()) {
/*
* Set IP options for a non-interactive connection. Use
* IPTOS_THROUGHPUT.
*/
int throughput = IPTOS_THROUGHPUT;
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
sizeof(throughput)) < 0)
error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
@ -1295,3 +1320,65 @@ packet_set_maxsize(int s)
max_packet_size = s;
return s;
}
/*
* 9.2. Ignored Data Message
*
* byte SSH_MSG_IGNORE
* string data
*
* All implementations MUST understand (and ignore) this message at any
* time (after receiving the protocol version). No implementation is
* required to send them. This message can be used as an additional
* protection measure against advanced traffic analysis techniques.
*/
/* size of current + ignore message should be n*sumlen bytes (w/o mac) */
void
packet_inject_ignore(int sumlen)
{
int blocksize, padlen, have, need, nb, mini, nbytes;
Enc *enc = NULL;
if (use_ssh2_packet_format == 0)
return;
have = buffer_len(&outgoing_packet);
debug2("packet_inject_ignore: current %d", have);
if (newkeys[MODE_OUT] != NULL)
enc = &newkeys[MODE_OUT]->enc;
blocksize = enc ? enc->cipher->block_size : 8;
padlen = blocksize - (have % blocksize);
if (padlen < 4)
padlen += blocksize;
have += padlen;
have /= blocksize; /* # of blocks for current message */
nb = roundup(sumlen, blocksize) / blocksize; /* blocks for both */
mini = roundup(5+1+4+4, blocksize) / blocksize; /* minsize ignore msg */
need = nb - (have % nb); /* blocks for ignore */
if (need <= mini)
need += nb;
nbytes = (need - mini) * blocksize; /* size of ignore payload */
debug2("packet_inject_ignore: block %d have %d nb %d mini %d need %d",
blocksize, have, nb, mini, need);
/* enqueue current message and append a ignore message */
packet_send();
packet_send_ignore(nbytes);
}
void
packet_send_ignore(int nbytes)
{
u_int32_t rand = 0;
int i;
packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE);
packet_put_int(nbytes);
for(i = 0; i < nbytes; i++) {
if (i % 4 == 0)
rand = arc4random();
packet_put_char(rand & 0xff);
rand >>= 8;
}
}

111
crypto/openssh/pathnames.h Normal file
View File

@ -0,0 +1,111 @@
/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#define ETCDIR "/etc"
#define _PATH_SSH_PIDDIR "/var/run"
/*
* System-wide file containing host keys of known hosts. This file should be
* world-readable.
*/
#define _PATH_SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
#define _PATH_SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
/*
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
* should be world-readable.
*/
#define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config"
#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key"
#define _PATH_DH_PRIMES ETCDIR "/primes"
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
/*
* The process id of the daemon listening for connections is saved here to
* make it easier to kill the correct daemon when necessary.
*/
#define _PATH_SSH_DAEMON_PID_FILE _PATH_SSH_PIDDIR "/sshd.pid"
/*
* The directory in user\'s home directory in which the files reside. The
* directory should be world-readable (though not all files are).
*/
#define _PATH_SSH_USER_DIR ".ssh"
/*
* Per-user file containing host keys of known hosts. This file need not be
* readable by anyone except the user him/herself, though this does not
* contain anything particularly secret.
*/
#define _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts"
#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
/*
* Name of the default file containing client-side authentication key. This
* file should only be readable by the user him/herself.
*/
#define _PATH_SSH_CLIENT_IDENTITY ".ssh/identity"
#define _PATH_SSH_CLIENT_ID_DSA ".ssh/id_dsa"
#define _PATH_SSH_CLIENT_ID_RSA ".ssh/id_rsa"
/*
* Configuration file in user\'s home directory. This file need not be
* readable by anyone but the user him/herself, but does not contain anything
* particularly secret. If the user\'s home directory resides on an NFS
* volume where root is mapped to nobody, this may need to be world-readable.
*/
#define _PATH_SSH_USER_CONFFILE ".ssh/config"
/*
* File containing a list of those rsa keys that permit logging in as this
* user. This file need not be readable by anyone but the user him/herself,
* but does not contain anything particularly secret. If the user\'s home
* directory resides on an NFS volume where root is mapped to nobody, this
* may need to be world-readable. (This file is read by the daemon which is
* running as root.)
*/
#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
/*
* Per-user and system-wide ssh "rc" files. These files are executed with
* /bin/sh before starting the shell or command if they exist. They will be
* passed "proto cookie" as arguments if X11 forwarding with spoofing is in
* use. xauth will be run if neither of these exists.
*/
#define _PATH_SSH_USER_RC ".ssh/rc"
#define _PATH_SSH_SYSTEM_RC ETCDIR "/sshrc"
/*
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
* ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
*/
#define _PATH_SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
#define _PATH_RHOSTS_EQUIV "/etc/hosts.equiv"
/*
* Default location of askpass
*/
#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
/* for scp */
#define _PATH_CP "cp"
/* for sftp */
#define _PATH_SFTP_SERVER "/usr/libexec/sftp-server"
#define _PATH_LS "ls"

View File

@ -25,19 +25,19 @@
#include "includes.h"
#include "uuencode.h"
RCSID("$OpenBSD: radix.c,v 1.13 2000/09/07 20:27:52 deraadt Exp $");
RCSID("$OpenBSD: radix.c,v 1.15 2001/01/16 23:58:09 deraadt Exp $");
#ifdef AFS
#include <krb.h>
typedef unsigned char my_u_char;
typedef unsigned int my_u_int32_t;
typedef unsigned short my_u_short;
typedef u_char my_u_char;
typedef u_int my_u_int32_t;
typedef u_short my_u_short;
/* Nasty macros from BIND-4.9.2 */
#define GETSHORT(s, cp) { \
register my_u_char *t_cp = (my_u_char*)(cp); \
register my_u_char *t_cp = (my_u_char *)(cp); \
(s) = (((my_u_short)t_cp[0]) << 8) \
| (((my_u_short)t_cp[1])) \
; \
@ -45,7 +45,7 @@ typedef unsigned short my_u_short;
}
#define GETLONG(l, cp) { \
register my_u_char *t_cp = (my_u_char*)(cp); \
register my_u_char *t_cp = (my_u_char *)(cp); \
(l) = (((my_u_int32_t)t_cp[0]) << 24) \
| (((my_u_int32_t)t_cp[1]) << 16) \
| (((my_u_int32_t)t_cp[2]) << 8) \
@ -56,7 +56,7 @@ typedef unsigned short my_u_short;
#define PUTSHORT(s, cp) { \
register my_u_short t_s = (my_u_short)(s); \
register my_u_char *t_cp = (my_u_char*)(cp); \
register my_u_char *t_cp = (my_u_char *)(cp); \
*t_cp++ = t_s >> 8; \
*t_cp = t_s; \
(cp) += 2; \
@ -64,7 +64,7 @@ typedef unsigned short my_u_short;
#define PUTLONG(l, cp) { \
register my_u_int32_t t_l = (my_u_int32_t)(l); \
register my_u_char *t_cp = (my_u_char*)(cp); \
register my_u_char *t_cp = (my_u_char *)(cp); \
*t_cp++ = t_l >> 24; \
*t_cp++ = t_l >> 16; \
*t_cp++ = t_l >> 8; \
@ -73,9 +73,9 @@ typedef unsigned short my_u_short;
}
#define GETSTRING(s, p, p_l) { \
register char* p_targ = (p) + p_l; \
register char* s_c = (s); \
register char* p_c = (p); \
register char *p_targ = (p) + p_l; \
register char *s_c = (s); \
register char *p_c = (p); \
while (*p_c && (p_c < p_targ)) { \
*s_c++ = *p_c++; \
} \
@ -89,7 +89,7 @@ typedef unsigned short my_u_short;
int
creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
creds_to_radix(CREDENTIALS *creds, u_char *buf, size_t buflen)
{
char *p, *s;
int len;
@ -123,8 +123,8 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
PUTLONG(creds->issue_date, p);
{
unsigned int endTime;
endTime = (unsigned int) krb_life_to_time(creds->issue_date,
u_int endTime;
endTime = (u_int) krb_life_to_time(creds->issue_date,
creds->lifetime);
PUTLONG(endTime, p);
}
@ -139,7 +139,7 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
p += creds->ticket_st.length;
len = p - temp;
return (uuencode((unsigned char *)temp, len, (char *)buf, buflen));
return (uuencode((u_char *)temp, len, (char *)buf, buflen));
}
int
@ -151,7 +151,7 @@ radix_to_creds(const char *buf, CREDENTIALS *creds)
char version;
char temp[2048];
len = uudecode(buf, (unsigned char *)temp, sizeof(temp));
len = uudecode(buf, (u_char *)temp, sizeof(temp));
if (len < 0)
return 0;
@ -184,7 +184,7 @@ radix_to_creds(const char *buf, CREDENTIALS *creds)
GETLONG(creds->issue_date, p);
len -= 4;
{
unsigned int endTime;
u_int endTime;
GETLONG(endTime, p);
len -= 4;
creds->lifetime = krb_time_to_life(creds->issue_date, endTime);

28
crypto/openssh/radix.h Normal file
View File

@ -0,0 +1,28 @@
/* $OpenBSD: radix.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/*
* Copyright (c) 1999 Dug Song. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
int creds_to_radix(CREDENTIALS * creds, u_char *buf, size_t buflen);
int radix_to_creds(const char *buf, CREDENTIALS * creds);

View File

@ -32,11 +32,58 @@
*/
#include "includes.h"
RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $");
RCSID("$OpenBSD: readpass.c,v 1.15 2001/04/18 21:57:41 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "cli.h"
#include "readpass.h"
#include "pathnames.h"
#include "log.h"
#include "atomicio.h"
#include "ssh.h"
char *
ssh_askpass(char *askpass, char *msg)
{
pid_t pid;
size_t len;
char *nl, *pass;
int p[2], status;
char buf[1024];
if (fflush(stdout) != 0)
error("ssh_askpass: fflush: %s", strerror(errno));
if (askpass == NULL)
fatal("internal error: askpass undefined");
if (pipe(p) < 0)
fatal("ssh_askpass: pipe: %s", strerror(errno));
if ((pid = fork()) < 0)
fatal("ssh_askpass: fork: %s", strerror(errno));
if (pid == 0) {
seteuid(getuid());
setuid(getuid());
close(p[0]);
if (dup2(p[1], STDOUT_FILENO) < 0)
fatal("ssh_askpass: dup2: %s", strerror(errno));
execlp(askpass, askpass, msg, (char *) 0);
fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
}
close(p[1]);
len = read(p[0], buf, sizeof buf);
close(p[0]);
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
if (len <= 1)
return xstrdup("");
nl = strchr(buf, '\n');
if (nl)
*nl = '\0';
pass = xstrdup(buf);
memset(buf, 0, sizeof(buf));
return pass;
}
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
@ -51,5 +98,27 @@ RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $");
char *
read_passphrase(char *prompt, int from_stdin)
{
char *askpass = NULL;
int use_askpass = 0, ttyfd;
if (from_stdin) {
if (!isatty(STDIN_FILENO))
use_askpass = 1;
} else {
ttyfd = open("/dev/tty", O_RDWR);
if (ttyfd >= 0)
close(ttyfd);
else
use_askpass = 1;
}
if (use_askpass && getenv("DISPLAY")) {
if (getenv(SSH_ASKPASS_ENV))
askpass = getenv(SSH_ASKPASS_ENV);
else
askpass = _PATH_SSH_ASKPASS_DEFAULT;
return ssh_askpass(askpass, prompt);
}
return cli_read_passphrase(prompt, from_stdin, 0);
}

20
crypto/openssh/readpass.h Normal file
View File

@ -0,0 +1,20 @@
/* $OpenBSD: readpass.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
* from_stdin is true, the passphrase will be read from stdin instead.
*/
char *read_passphrase(char *prompt, int from_stdin);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: rijndael.c,v 1.2 2000/10/15 14:14:01 markus Exp $ */
/* $OpenBSD: rijndael.c,v 1.7 2001/02/04 15:32:24 stevesk Exp $ */
/* This is an independent implementation of the encryption algorithm: */
/* */
@ -52,21 +52,14 @@ void gen_tabs __P((void));
/* Invert byte order in a 32 bit variable */
#define bswap(x) (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00)
#define bswap(x) ((rotl(x, 8) & 0x00ff00ff) | (rotr(x, 8) & 0xff00ff00))
/* Extract byte from a 32 bit quantity (little endian notation) */
/* Extract byte from a 32 bit quantity (little endian notation) */
#define byte(x,n) ((u1byte)((x) >> (8 * n)))
#if BYTE_ORDER != LITTLE_ENDIAN
#define BLOCK_SWAP
#endif
/* For inverting byte order in input/output 32 bit words if needed */
#ifdef BLOCK_SWAP
#define BYTE_SWAP
#define WORD_SWAP
#endif
#ifdef BYTE_SWAP
@ -75,84 +68,6 @@ void gen_tabs __P((void));
#define io_swap(x) (x)
#endif
/* For inverting the byte order of input/output blocks if needed */
#ifdef WORD_SWAP
#define get_block(x) \
((u4byte*)(x))[0] = io_swap(in_blk[3]); \
((u4byte*)(x))[1] = io_swap(in_blk[2]); \
((u4byte*)(x))[2] = io_swap(in_blk[1]); \
((u4byte*)(x))[3] = io_swap(in_blk[0])
#define put_block(x) \
out_blk[3] = io_swap(((u4byte*)(x))[0]); \
out_blk[2] = io_swap(((u4byte*)(x))[1]); \
out_blk[1] = io_swap(((u4byte*)(x))[2]); \
out_blk[0] = io_swap(((u4byte*)(x))[3])
#define get_key(x,len) \
((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \
((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \
switch((((len) + 63) / 64)) { \
case 2: \
((u4byte*)(x))[0] = io_swap(in_key[3]); \
((u4byte*)(x))[1] = io_swap(in_key[2]); \
((u4byte*)(x))[2] = io_swap(in_key[1]); \
((u4byte*)(x))[3] = io_swap(in_key[0]); \
break; \
case 3: \
((u4byte*)(x))[0] = io_swap(in_key[5]); \
((u4byte*)(x))[1] = io_swap(in_key[4]); \
((u4byte*)(x))[2] = io_swap(in_key[3]); \
((u4byte*)(x))[3] = io_swap(in_key[2]); \
((u4byte*)(x))[4] = io_swap(in_key[1]); \
((u4byte*)(x))[5] = io_swap(in_key[0]); \
break; \
case 4: \
((u4byte*)(x))[0] = io_swap(in_key[7]); \
((u4byte*)(x))[1] = io_swap(in_key[6]); \
((u4byte*)(x))[2] = io_swap(in_key[5]); \
((u4byte*)(x))[3] = io_swap(in_key[4]); \
((u4byte*)(x))[4] = io_swap(in_key[3]); \
((u4byte*)(x))[5] = io_swap(in_key[2]); \
((u4byte*)(x))[6] = io_swap(in_key[1]); \
((u4byte*)(x))[7] = io_swap(in_key[0]); \
}
#else
#define get_block(x) \
((u4byte*)(x))[0] = io_swap(in_blk[0]); \
((u4byte*)(x))[1] = io_swap(in_blk[1]); \
((u4byte*)(x))[2] = io_swap(in_blk[2]); \
((u4byte*)(x))[3] = io_swap(in_blk[3])
#define put_block(x) \
out_blk[0] = io_swap(((u4byte*)(x))[0]); \
out_blk[1] = io_swap(((u4byte*)(x))[1]); \
out_blk[2] = io_swap(((u4byte*)(x))[2]); \
out_blk[3] = io_swap(((u4byte*)(x))[3])
#define get_key(x,len) \
((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \
((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \
switch((((len) + 63) / 64)) { \
case 4: \
((u4byte*)(x))[6] = io_swap(in_key[6]); \
((u4byte*)(x))[7] = io_swap(in_key[7]); \
case 3: \
((u4byte*)(x))[4] = io_swap(in_key[4]); \
((u4byte*)(x))[5] = io_swap(in_key[5]); \
case 2: \
((u4byte*)(x))[0] = io_swap(in_key[0]); \
((u4byte*)(x))[1] = io_swap(in_key[1]); \
((u4byte*)(x))[2] = io_swap(in_key[2]); \
((u4byte*)(x))[3] = io_swap(in_key[3]); \
}
#endif
#define LARGE_TABLES
u1byte pow_tab[256];
@ -174,15 +89,15 @@ u4byte tab_gen = 0;
#define f_rn(bo, bi, n, k) \
bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rn(bo, bi, n, k) \
bo[n] = it_tab[0][byte(bi[n],0)] ^ \
it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
#ifdef LARGE_TABLES
@ -194,15 +109,15 @@ u4byte tab_gen = 0;
#define f_rl(bo, bi, n, k) \
bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rl(bo, bi, n, k) \
bo[n] = il_tab[0][byte(bi[n],0)] ^ \
il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
#else
@ -214,15 +129,15 @@ u4byte tab_gen = 0;
#define f_rl(bo, bi, n, k) \
bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
#define i_rl(bo, bi, n, k) \
bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
#endif
@ -245,7 +160,7 @@ gen_tabs(void)
log_tab[1] = 0; p = 1;
for(i = 0; i < 10; ++i) {
rco_tab[i] = p;
rco_tab[i] = p;
p = (p << 1) ^ (p & 0x80 ? 0x1b : 0);
}
@ -257,19 +172,19 @@ gen_tabs(void)
/* least significant end of a byte. */
for(i = 0; i < 256; ++i) {
p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q ^ 0x63;
p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q;
q = (q >> 7) | (q << 1); p ^= q ^ 0x63;
sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i;
}
for(i = 0; i < 256; ++i) {
p = sbx_tab[i];
p = sbx_tab[i];
#ifdef LARGE_TABLES
#ifdef LARGE_TABLES
t = p; fl_tab[0][i] = t;
fl_tab[1][i] = rotl(t, 8);
fl_tab[2][i] = rotl(t, 16);
@ -279,30 +194,30 @@ gen_tabs(void)
((u4byte)p << 8) |
((u4byte)p << 16) |
((u4byte)ff_mult(3, p) << 24);
ft_tab[0][i] = t;
ft_tab[1][i] = rotl(t, 8);
ft_tab[2][i] = rotl(t, 16);
ft_tab[3][i] = rotl(t, 24);
p = isb_tab[i];
p = isb_tab[i];
#ifdef LARGE_TABLES
t = p; il_tab[0][i] = t;
il_tab[1][i] = rotl(t, 8);
il_tab[2][i] = rotl(t, 16);
#ifdef LARGE_TABLES
t = p; il_tab[0][i] = t;
il_tab[1][i] = rotl(t, 8);
il_tab[2][i] = rotl(t, 16);
il_tab[3][i] = rotl(t, 24);
#endif
#endif
t = ((u4byte)ff_mult(14, p)) |
((u4byte)ff_mult( 9, p) << 8) |
((u4byte)ff_mult(13, p) << 16) |
((u4byte)ff_mult(11, p) << 24);
it_tab[0][i] = t;
it_tab[1][i] = rotl(t, 8);
it_tab[2][i] = rotl(t, 16);
it_tab[3][i] = rotl(t, 24);
it_tab[0][i] = t;
it_tab[1][i] = rotl(t, 8);
it_tab[2][i] = rotl(t, 16);
it_tab[3][i] = rotl(t, 24);
}
tab_gen = 1;
@ -317,8 +232,8 @@ gen_tabs(void)
t = w ^ (x); \
(y) = u ^ v ^ w; \
(y) ^= rotr(u ^ t, 8) ^ \
rotr(v ^ t, 16) ^ \
rotr(t,24)
rotr(v ^ t, 16) ^ \
rotr(t,24)
/* initialise the key schedule from the user supplied key */
@ -356,7 +271,7 @@ gen_tabs(void)
rijndael_ctx *
rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len,
int encrypt)
{
{
u4byte i, t, u, v, w;
u4byte *e_key = ctx->e_key;
u4byte *d_key = ctx->d_key;
@ -368,25 +283,25 @@ rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len,
ctx->k_len = (key_len + 31) / 32;
e_key[0] = in_key[0]; e_key[1] = in_key[1];
e_key[2] = in_key[2]; e_key[3] = in_key[3];
e_key[0] = io_swap(in_key[0]); e_key[1] = io_swap(in_key[1]);
e_key[2] = io_swap(in_key[2]); e_key[3] = io_swap(in_key[3]);
switch(ctx->k_len) {
case 4: t = e_key[3];
for(i = 0; i < 10; ++i)
case 4: t = e_key[3];
for(i = 0; i < 10; ++i)
loop4(i);
break;
break;
case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5];
for(i = 0; i < 8; ++i)
case 6: e_key[4] = io_swap(in_key[4]); t = e_key[5] = io_swap(in_key[5]);
for(i = 0; i < 8; ++i)
loop6(i);
break;
break;
case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5];
e_key[6] = in_key[6]; t = e_key[7] = in_key[7];
for(i = 0; i < 7; ++i)
case 8: e_key[4] = io_swap(in_key[4]); e_key[5] = io_swap(in_key[5]);
e_key[6] = io_swap(in_key[6]); t = e_key[7] = io_swap(in_key[7]);
for(i = 0; i < 7; ++i)
loop8(i);
break;
break;
}
if (!encrypt) {
@ -418,13 +333,15 @@ rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len,
void
rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
{
{
u4byte k_len = ctx->k_len;
u4byte *e_key = ctx->e_key;
u4byte b0[4], b1[4], *kp;
b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1];
b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3];
b0[0] = io_swap(in_blk[0]) ^ e_key[0];
b0[1] = io_swap(in_blk[1]) ^ e_key[1];
b0[2] = io_swap(in_blk[2]) ^ e_key[2];
b0[3] = io_swap(in_blk[3]) ^ e_key[3];
kp = e_key + 4;
@ -442,8 +359,8 @@ rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
f_nround(b1, b0, kp); f_lround(b0, b1, kp);
out_blk[0] = b0[0]; out_blk[1] = b0[1];
out_blk[2] = b0[2]; out_blk[3] = b0[3];
out_blk[0] = io_swap(b0[0]); out_blk[1] = io_swap(b0[1]);
out_blk[2] = io_swap(b0[2]); out_blk[3] = io_swap(b0[3]);
}
/* decrypt a block of text */
@ -463,14 +380,16 @@ rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
void
rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
{
{
u4byte b0[4], b1[4], *kp;
u4byte k_len = ctx->k_len;
u4byte *e_key = ctx->e_key;
u4byte *d_key = ctx->d_key;
b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25];
b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27];
b0[0] = io_swap(in_blk[0]) ^ e_key[4 * k_len + 24];
b0[1] = io_swap(in_blk[1]) ^ e_key[4 * k_len + 25];
b0[2] = io_swap(in_blk[2]) ^ e_key[4 * k_len + 26];
b0[3] = io_swap(in_blk[3]) ^ e_key[4 * k_len + 27];
kp = d_key + 4 * (k_len + 5);
@ -488,6 +407,6 @@ rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
i_nround(b1, b0, kp); i_lround(b0, b1, kp);
out_blk[0] = b0[0]; out_blk[1] = b0[1];
out_blk[2] = b0[2]; out_blk[3] = b0[3];
out_blk[0] = io_swap(b0[0]); out_blk[1] = io_swap(b0[1]);
out_blk[2] = io_swap(b0[2]); out_blk[3] = io_swap(b0[3]);
}

View File

@ -1,3 +1,19 @@
/* $OpenBSD: rijndael.h,v 1.7 2001/03/01 03:38:33 deraadt Exp $ */
/* This is an independent implementation of the encryption algorithm: */
/* */
/* RIJNDAEL by Joan Daemen and Vincent Rijmen */
/* */
/* which is a candidate algorithm in the Advanced Encryption Standard */
/* programme of the US National Institute of Standards and Technology. */
/* */
/* Copyright in this implementation is held by Dr B R Gladman but I */
/* hereby give permission for its free direct or derivative use subject */
/* to acknowledgment of its origin and compliance with any conditions */
/* that the originators of the algorithm place on its exploitation. */
/* */
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
#ifndef _RIJNDAEL_H_
#define _RIJNDAEL_H_

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Parts from:
*
* Copyright (c) 1983, 1990, 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "includes.h"
RCSID("$OpenBSD: scp-common.c,v 1.1 2001/04/16 02:31:43 mouring Exp $");
char *
cleanhostname(host)
char *host;
{
if (*host == '[' && host[strlen(host) - 1] == ']') {
host[strlen(host) - 1] = '\0';
return (host + 1);
} else
return host;
}
char *
colon(cp)
char *cp;
{
int flag = 0;
if (*cp == ':') /* Leading colon is part of file name. */
return (0);
if (*cp == '[')
flag = 1;
for (; *cp; ++cp) {
if (*cp == '@' && *(cp+1) == '[')
flag = 1;
if (*cp == ']' && *(cp+1) == ':' && flag)
return (cp+1);
if (*cp == ':' && !flag)
return (cp);
if (*cp == '/')
return (0);
}
return (0);
}

View File

@ -0,0 +1,64 @@
/* $OpenBSD: scp-common.h,v 1.1 2001/04/16 02:31:43 mouring Exp $ */
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Parts from:
*
* Copyright (c) 1983, 1990, 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
char *cleanhostname(char *host);
char *colon(char *cp);

View File

@ -9,7 +9,7 @@
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
.\" $OpenBSD: scp.1,v 1.13 2000/10/16 09:38:44 djm Exp $
.\" $OpenBSD: scp.1,v 1.14 2001/02/04 11:11:53 djm Exp $
.\"
.Dd September 25, 1999
.Dt SCP 1
@ -129,6 +129,7 @@ program in BSD source code from the Regents of the University of
California.
.Sh SEE ALSO
.Xr rcp 1 ,
.Xr sftp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,

View File

@ -14,8 +14,8 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -75,12 +75,13 @@
*/
#include "includes.h"
RCSID("$OpenBSD: scp.c,v 1.43 2000/10/18 18:23:02 markus Exp $");
RCSID("$OpenBSD: scp.c,v 1.68 2001/04/22 12:34:05 markus Exp $");
#include "ssh.h"
#include "xmalloc.h"
#define _PATH_CP "cp"
#include "atomicio.h"
#include "pathnames.h"
#include "log.h"
#include "scp-common.h"
/* For progressmeter() -- number of seconds before xfer considered "stalled" */
#define STALLTIME 5
@ -99,7 +100,7 @@ void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2)));
static struct timeval start;
/* Number of bytes of current file transferred so far. */
volatile unsigned long statbytes;
volatile off_t statbytes;
/* Total size of current file. */
off_t totalbytes = 0;
@ -110,14 +111,11 @@ char *curfile;
/* This is set to non-zero to enable verbose mode. */
int verbose_mode = 0;
/* This is set to non-zero if compression is desired. */
int compress = 0;
/* This is set to zero if the progressmeter is not desired. */
int showprogress = 1;
/* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = SSH_PROGRAM;
char *ssh_program = _PATH_SSH_PROGRAM;
/* This is the list of arguments that scp passes to ssh */
struct {
@ -185,28 +183,12 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
return 0;
}
void
fatal(const char *fmt,...)
{
va_list ap;
char buf[1024];
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", buf);
exit(255);
}
typedef struct {
int cnt;
char *buf;
} BUF;
extern int iamremote;
BUF *allocbuf(BUF *, int, int);
char *colon(char *);
void lostconn(int);
void nospace(void);
int okname(char *);
@ -245,7 +227,7 @@ main(argc, argv)
addargs("-oFallBackToRsh no");
fflag = tflag = 0;
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF)
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != -1)
switch (ch) {
/* User-visible flags. */
case '4':
@ -292,7 +274,6 @@ main(argc, argv)
iamremote = 1;
tflag = 1;
break;
case '?':
default:
usage();
}
@ -308,7 +289,7 @@ main(argc, argv)
remin = STDIN_FILENO;
remout = STDOUT_FILENO;
if (fflag) {
if (fflag) {
/* Follow "protocol", send data. */
(void) response();
source(argc, argv);
@ -326,7 +307,8 @@ main(argc, argv)
remin = remout = -1;
/* Command to be executed on remote system using "ssh". */
(void) sprintf(cmd, "scp%s%s%s%s", verbose_mode ? " -v" : "",
(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
verbose_mode ? " -v" : "",
iamrecursive ? " -r" : "", pflag ? " -p" : "",
targetshouldbedirectory ? " -d" : "");
@ -342,17 +324,6 @@ main(argc, argv)
exit(errs != 0);
}
char *
cleanhostname(host)
char *host;
{
if (*host == '[' && host[strlen(host) - 1] == ']') {
host[strlen(host) - 1] = '\0';
return (host + 1);
} else
return host;
}
void
toremote(targ, argc, argv)
char *targ, *argv[];
@ -397,20 +368,22 @@ toremote(targ, argc, argv)
suser = pwd->pw_name;
else if (!okname(suser))
continue;
(void) sprintf(bp,
"%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
suser, host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
snprintf(bp, len,
"%s%s -x -o'FallBackToRsh no' -n "
"-l %s %s %s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
suser, host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
} else {
host = cleanhostname(argv[i]);
(void) sprintf(bp,
"exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
snprintf(bp, len,
"exec %s%s -x -o'FallBackToRsh no' -n %s "
"%s %s '%s%s%s:%s'",
ssh_program, verbose_mode ? " -v" : "",
host, cmd, src,
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
}
if (verbose_mode)
fprintf(stderr, "Executing: %s\n", bp);
@ -420,7 +393,7 @@ toremote(targ, argc, argv)
if (remin == -1) {
len = strlen(targ) + CMDNEEDS + 20;
bp = xmalloc(len);
(void) sprintf(bp, "%s -t %s", cmd, targ);
(void) snprintf(bp, len, "%s -t %s", cmd, targ);
host = cleanhostname(thost);
if (do_cmd(host, tuser, bp, &remin,
&remout, argc) < 0)
@ -447,7 +420,7 @@ tolocal(argc, argv)
len = strlen(_PATH_CP) + strlen(argv[i]) +
strlen(argv[argc - 1]) + 20;
bp = xmalloc(len);
(void) sprintf(bp, "exec %s%s%s %s %s", _PATH_CP,
(void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
iamrecursive ? " -r" : "", pflag ? " -p" : "",
argv[i], argv[argc - 1]);
if (verbose_mode)
@ -474,7 +447,7 @@ tolocal(argc, argv)
host = cleanhostname(host);
len = strlen(src) + CMDNEEDS + 20;
bp = xmalloc(len);
(void) sprintf(bp, "%s -f %s", cmd, src);
(void) snprintf(bp, len, "%s -f %s", cmd, src);
if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) {
(void) xfree(bp);
++errs;
@ -495,13 +468,17 @@ source(argc, argv)
struct stat stb;
static BUF buffer;
BUF *bp;
off_t i;
int amt, fd, haderr, indx, result;
off_t i, amt, result;
int fd, haderr, indx;
char *last, *name, buf[2048];
int len;
for (indx = 0; indx < argc; ++indx) {
name = argv[indx];
statbytes = 0;
len = strlen(name);
while (len > 1 && name[len-1] == '/')
name[--len] = '\0';
if ((fd = open(name, O_RDONLY, 0)) < 0)
goto syserr;
if (fstat(fd, &stb) < 0) {
@ -531,18 +508,17 @@ syserr: run_err("%s: %s", name, strerror(errno));
* Make it compatible with possible future
* versions expecting microseconds.
*/
(void) sprintf(buf, "T%lu 0 %lu 0\n",
(unsigned long) stb.st_mtime,
(unsigned long) stb.st_atime);
(void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
(u_long) stb.st_mtime,
(u_long) stb.st_atime);
(void) atomicio(write, remout, buf, strlen(buf));
if (response() < 0)
goto next;
}
#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
(void) sprintf(buf, "C%04o %lu %s\n",
(unsigned int) (stb.st_mode & FILEMODEMASK),
(unsigned long) stb.st_size,
last);
snprintf(buf, sizeof buf, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK),
(long long)stb.st_size, last);
if (verbose_mode) {
fprintf(stderr, "Sending file modes: %s", buf);
fflush(stderr);
@ -609,17 +585,17 @@ rsource(name, statp)
else
last++;
if (pflag) {
(void) sprintf(path, "T%lu 0 %lu 0\n",
(unsigned long) statp->st_mtime,
(unsigned long) statp->st_atime);
(void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n",
(u_long) statp->st_mtime,
(u_long) statp->st_atime);
(void) atomicio(write, remout, path, strlen(path));
if (response() < 0) {
closedir(dirp);
return;
}
}
(void) sprintf(path, "D%04o %d %.1024s\n",
(unsigned int) (statp->st_mode & FILEMODEMASK), 0, last);
(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
(u_int) (statp->st_mode & FILEMODEMASK), 0, last);
if (verbose_mode)
fprintf(stderr, "Entering directory: %s", path);
(void) atomicio(write, remout, path, strlen(path));
@ -627,7 +603,7 @@ rsource(name, statp)
closedir(dirp);
return;
}
while ((dp = readdir(dirp))) {
while ((dp = readdir(dirp)) != NULL) {
if (dp->d_ino == 0)
continue;
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
@ -636,7 +612,7 @@ rsource(name, statp)
run_err("%s/%s: name too long", name, dp->d_name);
continue;
}
(void) sprintf(path, "%s/%s", name, dp->d_name);
(void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
vect[0] = path;
source(1, vect);
}
@ -661,9 +637,10 @@ sink(argc, argv)
off_t size;
int setimes, targisdir, wrerrno = 0;
char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
int dummy_usec;
struct timeval tv[2];
#define atime tv[0]
#define mtime tv[1]
#define SCREWUP(str) { why = str; goto screwup; }
setimes = targisdir = 0;
@ -697,7 +674,7 @@ sink(argc, argv)
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0)
(void) atomicio(write, STDERR_FILENO,
buf + 1, strlen(buf + 1));
buf + 1, strlen(buf + 1));
if (buf[0] == '\02')
exit(1);
++errs;
@ -710,25 +687,21 @@ sink(argc, argv)
if (ch == '\n')
*--cp = 0;
#define getnum(t) (t) = 0; \
while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0');
cp = buf;
if (*cp == 'T') {
setimes++;
cp++;
getnum(tv[1].tv_sec);
if (*cp++ != ' ')
mtime.tv_sec = strtol(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("mtime.sec not delimited");
getnum(dummy_usec);
tv[1].tv_usec = 0;
if (*cp++ != ' ')
mtime.tv_usec = strtol(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("mtime.usec not delimited");
getnum(tv[0].tv_sec);
if (*cp++ != ' ')
atime.tv_sec = strtol(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("atime.sec not delimited");
getnum(dummy_usec);
tv[0].tv_usec = 0;
if (*cp++ != '\0')
atime.tv_usec = strtol(cp, &cp, 10);
if (!cp || *cp++ != '\0')
SCREWUP("atime.usec not delimited");
(void) atomicio(write, remout, "", 1);
continue;
@ -756,7 +729,7 @@ sink(argc, argv)
if (*cp++ != ' ')
SCREWUP("mode not delimited");
for (size = 0; *cp >= '0' && *cp <= '9';)
for (size = 0; isdigit(*cp);)
size = size * 10 + (*cp++ - '0');
if (*cp++ != ' ')
SCREWUP("size not delimited");
@ -766,9 +739,13 @@ sink(argc, argv)
size_t need;
need = strlen(targ) + strlen(cp) + 250;
if (need > cursize)
if (need > cursize) {
if (namebuf)
xfree(namebuf);
namebuf = xmalloc(need);
(void) sprintf(namebuf, "%s%s%s", targ,
cursize = need;
}
(void) snprintf(namebuf, need, "%s%s%s", targ,
*targ ? "/" : "", cp);
np = namebuf;
} else
@ -791,16 +768,18 @@ sink(argc, argv)
if (mkdir(np, mode | S_IRWXU) < 0)
goto bad;
}
vect[0] = np;
vect[0] = xstrdup(np);
sink(1, vect);
if (setimes) {
setimes = 0;
if (utimes(np, tv) < 0)
if (utimes(vect[0], tv) < 0)
run_err("%s: set times: %s",
np, strerror(errno));
vect[0], strerror(errno));
}
if (mod_flag)
(void) chmod(np, mode);
(void) chmod(vect[0], mode);
if (vect[0])
xfree(vect[0]);
continue;
}
omode = mode;
@ -833,7 +812,7 @@ bad: run_err("%s: %s", np, strerror(errno));
continue;
} else if (j <= 0) {
run_err("%s", j ? strerror(errno) :
"dropped connection");
"dropped connection");
exit(1);
}
amt -= j;
@ -870,12 +849,12 @@ bad: run_err("%s: %s", np, strerror(errno));
if (exists || omode != mode)
if (fchmod(ofd, omode))
run_err("%s: set mode: %s",
np, strerror(errno));
np, strerror(errno));
} else {
if (!exists && omode != mode)
if (fchmod(ofd, omode & ~mask))
run_err("%s: set mode: %s",
np, strerror(errno));
np, strerror(errno));
}
if (close(ofd) == -1) {
wrerr = YES;
@ -886,7 +865,7 @@ bad: run_err("%s: %s", np, strerror(errno));
setimes = 0;
if (utimes(np, tv) < 0) {
run_err("%s: set times: %s",
np, strerror(errno));
np, strerror(errno));
wrerr = DISPLAYED;
}
}
@ -943,8 +922,8 @@ void
usage()
{
(void) fprintf(stderr, "usage: scp "
"[-pqrvC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2; or:\n"
" scp [options] f1 ... fn directory\n");
"[-pqrvBC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2\n"
" or: scp [options] f1 ... fn directory\n");
exit(1);
}
@ -971,30 +950,6 @@ run_err(const char *fmt,...)
va_end(ap);
}
char *
colon(cp)
char *cp;
{
int flag = 0;
if (*cp == ':') /* Leading colon is part of file name. */
return (0);
if (*cp == '[')
flag = 1;
for (; *cp; ++cp) {
if (*cp == '@' && *(cp+1) == '[')
flag = 1;
if (*cp == ']' && *(cp+1) == ':' && flag)
return (cp+1);
if (*cp == ':' && !flag)
return (cp);
if (*cp == '/')
return (0);
}
return (0);
}
void
verifydir(cp)
char *cp;
@ -1022,7 +977,8 @@ okname(cp0)
c = *cp;
if (c & 0200)
goto bad;
if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-' && c != '.')
if (!isalpha(c) && !isdigit(c) &&
c != '_' && c != '-' && c != '.' && c != '+')
goto bad;
} while (*++cp);
return (1);
@ -1089,7 +1045,7 @@ updateprogressmeter(int ignore)
}
int
foregroundproc()
foregroundproc(void)
{
static pid_t pgrp = -1;
int ctty_pgrp;
@ -1147,9 +1103,9 @@ progressmeter(int flag)
i++;
abbrevsize >>= 10;
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5qd %c%c ",
(quad_t) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
'B');
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5llu %c%c ",
(unsigned long long) abbrevsize, prefixes[i],
prefixes[i] == ' ' ? ' ' : 'B');
timersub(&now, &lastupdate, &wait);
if (cursize > lastsize) {
@ -1164,16 +1120,17 @@ progressmeter(int flag)
timersub(&now, &start, &td);
elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes) {
if (flag != 1 &&
(statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
" --:-- ETA");
" --:-- ETA");
} else if (wait.tv_sec >= STALLTIME) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
" - stalled -");
" - stalled -");
} else {
if (flag != 1)
remaining =
(int)(totalbytes / (statbytes / elapsed) - elapsed);
remaining = (int)(totalbytes / (statbytes / elapsed) -
elapsed);
else
remaining = elapsed;

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.12 2001/04/16 02:31:48 mouring Exp $
.PATH: ${.CURDIR}/..
PROG= scp
@ -8,6 +10,6 @@ BINMODE?=555
BINDIR= /usr/bin
MAN= scp.1
SRCS= scp.c
SRCS= scp.c scp-common.c
.include <bsd.prog.mk>

View File

@ -0,0 +1,22 @@
/* $OpenBSD: serverloop.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Performs the interactive session. This handles data transmission between
* the client and the program. Note that the notion of stdin, stdout, and
* stderr in this function is sort of reversed: this function writes to stdin
* (of the child program), and reads from stdout and stderr (of the child
* program).
*/
void server_loop(pid_t pid, int fdin, int fdout, int fderr);
void server_loop2(void);

View File

@ -1,3 +1,5 @@
/* $OpenBSD: session.h,v 1.6 2001/03/21 11:43:45 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -24,11 +26,8 @@
#ifndef SESSION_H
#define SESSION_H
/* SSH1 */
void do_authenticated(struct passwd * pw);
void do_authenticated(Authctxt *ac);
/* SSH2 */
void do_authenticated2(void);
int session_open(int id);
void session_input_channel_req(int id, void *arg);
void session_close_by_pid(pid_t pid, int status);

View File

@ -0,0 +1,930 @@
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* XXX: memleaks */
/* XXX: signed vs unsigned */
/* XXX: redesign to allow concurrent overlapped operations */
/* XXX: we use fatal too much, error may be more appropriate in places */
/* XXX: copy between two remote sites */
#include "includes.h"
RCSID("$OpenBSD: sftp-client.c,v 1.16 2001/04/05 10:42:52 markus Exp $");
#include "ssh.h"
#include "buffer.h"
#include "bufaux.h"
#include "getput.h"
#include "xmalloc.h"
#include "log.h"
#include "atomicio.h"
#include "pathnames.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
/* How much data to read/write at at time during copies */
/* XXX: what should this be? */
#define COPY_SIZE 8192
/* Message ID */
static u_int msg_id = 1;
void
send_msg(int fd, Buffer *m)
{
int mlen = buffer_len(m);
int len;
Buffer oqueue;
buffer_init(&oqueue);
buffer_put_int(&oqueue, mlen);
buffer_append(&oqueue, buffer_ptr(m), mlen);
buffer_consume(m, mlen);
len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
if (len <= 0)
fatal("Couldn't send packet: %s", strerror(errno));
buffer_free(&oqueue);
}
void
get_msg(int fd, Buffer *m)
{
u_int len, msg_len;
unsigned char buf[4096];
len = atomicio(read, fd, buf, 4);
if (len == 0)
fatal("Connection closed");
else if (len == -1)
fatal("Couldn't read packet: %s", strerror(errno));
msg_len = GET_32BIT(buf);
if (msg_len > 256 * 1024)
fatal("Received message too long %d", msg_len);
while (msg_len) {
len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
if (len == 0)
fatal("Connection closed");
else if (len == -1)
fatal("Couldn't read packet: %s", strerror(errno));
msg_len -= len;
buffer_append(m, buf, len);
}
}
void
send_string_request(int fd, u_int id, u_int code, char *s,
u_int len)
{
Buffer msg;
buffer_init(&msg);
buffer_put_char(&msg, code);
buffer_put_int(&msg, id);
buffer_put_string(&msg, s, len);
send_msg(fd, &msg);
debug3("Sent message fd %d T:%d I:%d", fd, code, id);
buffer_free(&msg);
}
void
send_string_attrs_request(int fd, u_int id, u_int code, char *s,
u_int len, Attrib *a)
{
Buffer msg;
buffer_init(&msg);
buffer_put_char(&msg, code);
buffer_put_int(&msg, id);
buffer_put_string(&msg, s, len);
encode_attrib(&msg, a);
send_msg(fd, &msg);
debug3("Sent message fd %d T:%d I:%d", fd, code, id);
buffer_free(&msg);
}
u_int
get_status(int fd, int expected_id)
{
Buffer msg;
u_int type, id, status;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type != SSH2_FXP_STATUS)
fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
SSH2_FXP_STATUS, type);
status = buffer_get_int(&msg);
buffer_free(&msg);
debug3("SSH2_FXP_STATUS %d", status);
return(status);
}
char *
get_handle(int fd, u_int expected_id, u_int *len)
{
Buffer msg;
u_int type, id;
char *handle;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
error("Couldn't get handle: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_HANDLE)
fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
SSH2_FXP_HANDLE, type);
handle = buffer_get_string(&msg, len);
buffer_free(&msg);
return(handle);
}
Attrib *
get_decode_stat(int fd, u_int expected_id, int quiet)
{
Buffer msg;
u_int type, id;
Attrib *a;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received stat reply T:%d I:%d", type, id);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
if (quiet)
debug("Couldn't stat remote file: %s", fx2txt(status));
else
error("Couldn't stat remote file: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
SSH2_FXP_ATTRS, type);
}
a = decode_attrib(&msg);
buffer_free(&msg);
return(a);
}
int
do_init(int fd_in, int fd_out)
{
int type, version;
Buffer msg;
buffer_init(&msg);
buffer_put_char(&msg, SSH2_FXP_INIT);
buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
send_msg(fd_out, &msg);
buffer_clear(&msg);
get_msg(fd_in, &msg);
/* Expecting a VERSION reply */
if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
error("Invalid packet back from SSH2_FXP_INIT (type %d)",
type);
buffer_free(&msg);
return(-1);
}
version = buffer_get_int(&msg);
debug2("Remote version: %d", version);
/* Check for extensions */
while (buffer_len(&msg) > 0) {
char *name = buffer_get_string(&msg, NULL);
char *value = buffer_get_string(&msg, NULL);
debug2("Init extension: \"%s\"", name);
xfree(name);
xfree(value);
}
buffer_free(&msg);
return(version);
}
int
do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
{
u_int id, status;
Buffer msg;
buffer_init(&msg);
id = msg_id++;
buffer_put_char(&msg, SSH2_FXP_CLOSE);
buffer_put_int(&msg, id);
buffer_put_string(&msg, handle, handle_len);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't close file: %s", fx2txt(status));
buffer_free(&msg);
return(status);
}
int
do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
SFTP_DIRENT ***dir)
{
Buffer msg;
u_int type, id, handle_len, i, expected_id, ents = 0;
char *handle;
id = msg_id++;
buffer_init(&msg);
buffer_put_char(&msg, SSH2_FXP_OPENDIR);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, path);
send_msg(fd_out, &msg);
buffer_clear(&msg);
handle = get_handle(fd_in, id, &handle_len);
if (handle == NULL)
return(-1);
if (dir) {
ents = 0;
*dir = xmalloc(sizeof(**dir));
(*dir)[0] = NULL;
}
for(;;) {
int count;
id = expected_id = msg_id++;
debug3("Sending SSH2_FXP_READDIR I:%d", id);
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_READDIR);
buffer_put_int(&msg, id);
buffer_put_string(&msg, handle, handle_len);
send_msg(fd_out, &msg);
buffer_clear(&msg);
get_msg(fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received reply T:%d I:%d", type, id);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
debug3("Received SSH2_FXP_STATUS %d", status);
if (status == SSH2_FX_EOF) {
break;
} else {
error("Couldn't read directory: %s",
fx2txt(status));
do_close(fd_in, fd_out, handle, handle_len);
return(status);
}
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
SSH2_FXP_NAME, type);
count = buffer_get_int(&msg);
if (count == 0)
break;
debug3("Received %d SSH2_FXP_NAME responses", count);
for(i = 0; i < count; i++) {
char *filename, *longname;
Attrib *a;
filename = buffer_get_string(&msg, NULL);
longname = buffer_get_string(&msg, NULL);
a = decode_attrib(&msg);
if (printflag)
printf("%s\n", longname);
if (dir) {
*dir = xrealloc(*dir, sizeof(**dir) *
(ents + 2));
(*dir)[ents] = xmalloc(sizeof(***dir));
(*dir)[ents]->filename = xstrdup(filename);
(*dir)[ents]->longname = xstrdup(longname);
memcpy(&(*dir)[ents]->a, a, sizeof(*a));
(*dir)[++ents] = NULL;
}
xfree(filename);
xfree(longname);
}
}
buffer_free(&msg);
do_close(fd_in, fd_out, handle, handle_len);
xfree(handle);
return(0);
}
int
do_ls(int fd_in, int fd_out, char *path)
{
return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
}
int
do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
{
return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
}
void free_sftp_dirents(SFTP_DIRENT **s)
{
int i;
for(i = 0; s[i]; i++) {
xfree(s[i]->filename);
xfree(s[i]->longname);
xfree(s[i]);
}
xfree(s);
}
int
do_rm(int fd_in, int fd_out, char *path)
{
u_int status, id;
debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't delete file: %s", fx2txt(status));
return(status);
}
int
do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
{
u_int status, id;
id = msg_id++;
send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
strlen(path), a);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't create directory: %s", fx2txt(status));
return(status);
}
int
do_rmdir(int fd_in, int fd_out, char *path)
{
u_int status, id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't remove directory: %s", fx2txt(status));
return(status);
}
Attrib *
do_stat(int fd_in, int fd_out, char *path, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
return(get_decode_stat(fd_in, id, quiet));
}
Attrib *
do_lstat(int fd_in, int fd_out, char *path, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
return(get_decode_stat(fd_in, id, quiet));
}
Attrib *
do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
return(get_decode_stat(fd_in, id, quiet));
}
int
do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
{
u_int status, id;
id = msg_id++;
send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
strlen(path), a);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't setstat on \"%s\": %s", path,
fx2txt(status));
return(status);
}
int
do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
Attrib *a)
{
u_int status, id;
id = msg_id++;
send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
handle_len, a);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't fsetstat: %s", fx2txt(status));
return(status);
}
char *
do_realpath(int fd_in, int fd_out, char *path)
{
Buffer msg;
u_int type, expected_id, count, id;
char *filename, *longname;
Attrib *a;
expected_id = id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
buffer_init(&msg);
get_msg(fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int status = buffer_get_int(&msg);
error("Couldn't canonicalise: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
SSH2_FXP_NAME, type);
count = buffer_get_int(&msg);
if (count != 1)
fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
filename = buffer_get_string(&msg, NULL);
longname = buffer_get_string(&msg, NULL);
a = decode_attrib(&msg);
debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
xfree(longname);
buffer_free(&msg);
return(filename);
}
int
do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
{
Buffer msg;
u_int status, id;
buffer_init(&msg);
/* Send rename request */
id = msg_id++;
buffer_put_char(&msg, SSH2_FXP_RENAME);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, oldpath);
buffer_put_cstring(&msg, newpath);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
newpath);
buffer_free(&msg);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
fx2txt(status));
return(status);
}
int
do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
{
Buffer msg;
u_int status, id;
buffer_init(&msg);
/* Send rename request */
id = msg_id++;
buffer_put_char(&msg, SSH2_FXP_SYMLINK);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, oldpath);
buffer_put_cstring(&msg, newpath);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
newpath);
buffer_free(&msg);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK)
error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
fx2txt(status));
return(status);
}
char *
do_readlink(int fd_in, int fd_out, char *path)
{
Buffer msg;
u_int type, expected_id, count, id;
char *filename, *longname;
Attrib *a;
expected_id = id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
buffer_init(&msg);
get_msg(fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int status = buffer_get_int(&msg);
error("Couldn't readlink: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
SSH2_FXP_NAME, type);
count = buffer_get_int(&msg);
if (count != 1)
fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
filename = buffer_get_string(&msg, NULL);
longname = buffer_get_string(&msg, NULL);
a = decode_attrib(&msg);
debug3("SSH_FXP_READLINK %s -> %s", path, filename);
xfree(longname);
buffer_free(&msg);
return(filename);
}
int
do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
int pflag)
{
int local_fd;
u_int expected_id, handle_len, mode, type, id;
u_int64_t offset;
char *handle;
Buffer msg;
Attrib junk, *a;
int status;
a = do_stat(fd_in, fd_out, remote_path, 0);
if (a == NULL)
return(-1);
/* XXX: should we preserve set[ug]id? */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
mode = S_IWRITE | (a->perm & 0777);
else
mode = 0666;
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
(a->perm & S_IFDIR)) {
error("Cannot download a directory: %s", remote_path);
return(-1);
}
local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (local_fd == -1) {
error("Couldn't open local file \"%s\" for writing: %s",
local_path, strerror(errno));
return(-1);
}
buffer_init(&msg);
/* Send open request */
id = msg_id++;
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, remote_path);
buffer_put_int(&msg, SSH2_FXF_READ);
attrib_clear(&junk); /* Send empty attributes */
encode_attrib(&msg, &junk);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
handle = get_handle(fd_in, id, &handle_len);
if (handle == NULL) {
buffer_free(&msg);
close(local_fd);
return(-1);
}
/* Read from remote and write to local */
offset = 0;
for(;;) {
u_int len;
char *data;
id = expected_id = msg_id++;
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_READ);
buffer_put_int(&msg, id);
buffer_put_string(&msg, handle, handle_len);
buffer_put_int64(&msg, offset);
buffer_put_int(&msg, COPY_SIZE);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
id, (unsigned long long)offset, COPY_SIZE);
buffer_clear(&msg);
get_msg(fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received reply T:%d I:%d", type, id);
if (id != expected_id)
fatal("ID mismatch (%d != %d)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
status = buffer_get_int(&msg);
if (status == SSH2_FX_EOF)
break;
else {
error("Couldn't read from remote "
"file \"%s\" : %s", remote_path,
fx2txt(status));
do_close(fd_in, fd_out, handle, handle_len);
goto done;
}
} else if (type != SSH2_FXP_DATA) {
fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
SSH2_FXP_DATA, type);
}
data = buffer_get_string(&msg, &len);
if (len > COPY_SIZE)
fatal("Received more data than asked for %d > %d",
len, COPY_SIZE);
debug3("In read loop, got %d offset %llu", len,
(unsigned long long)offset);
if (atomicio(write, local_fd, data, len) != len) {
error("Couldn't write to \"%s\": %s", local_path,
strerror(errno));
do_close(fd_in, fd_out, handle, handle_len);
status = -1;
xfree(data);
goto done;
}
offset += len;
xfree(data);
}
status = do_close(fd_in, fd_out, handle, handle_len);
/* Override umask and utimes if asked */
if (pflag && fchmod(local_fd, mode) == -1)
error("Couldn't set mode on \"%s\": %s", local_path,
strerror(errno));
if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
struct timeval tv[2];
tv[0].tv_sec = a->atime;
tv[1].tv_sec = a->mtime;
tv[0].tv_usec = tv[1].tv_usec = 0;
if (utimes(local_path, tv) == -1)
error("Can't set times on \"%s\": %s", local_path,
strerror(errno));
}
done:
close(local_fd);
buffer_free(&msg);
xfree(handle);
return status;
}
int
do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
int pflag)
{
int local_fd;
u_int handle_len, id;
u_int64_t offset;
char *handle;
Buffer msg;
struct stat sb;
Attrib a;
int status;
if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
error("Couldn't open local file \"%s\" for reading: %s",
local_path, strerror(errno));
return(-1);
}
if (fstat(local_fd, &sb) == -1) {
error("Couldn't fstat local file \"%s\": %s",
local_path, strerror(errno));
close(local_fd);
return(-1);
}
stat_to_attrib(&sb, &a);
a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
a.perm &= 0777;
if (!pflag)
a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
buffer_init(&msg);
/* Send open request */
id = msg_id++;
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, remote_path);
buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
encode_attrib(&msg, &a);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
buffer_clear(&msg);
handle = get_handle(fd_in, id, &handle_len);
if (handle == NULL) {
close(local_fd);
buffer_free(&msg);
return(-1);
}
/* Read from local and write to remote */
offset = 0;
for(;;) {
int len;
char data[COPY_SIZE];
/*
* Can't use atomicio here because it returns 0 on EOF, thus losing
* the last block of the file
*/
do
len = read(local_fd, data, COPY_SIZE);
while ((len == -1) && (errno == EINTR || errno == EAGAIN));
if (len == -1)
fatal("Couldn't read from \"%s\": %s", local_path,
strerror(errno));
if (len == 0)
break;
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_WRITE);
buffer_put_int(&msg, ++id);
buffer_put_string(&msg, handle, handle_len);
buffer_put_int64(&msg, offset);
buffer_put_string(&msg, data, len);
send_msg(fd_out, &msg);
debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
id, (unsigned long long)offset, len);
status = get_status(fd_in, id);
if (status != SSH2_FX_OK) {
error("Couldn't write to remote file \"%s\": %s",
remote_path, fx2txt(status));
do_close(fd_in, fd_out, handle, handle_len);
close(local_fd);
goto done;
}
debug3("In write loop, got %d offset %llu", len,
(unsigned long long)offset);
offset += len;
}
if (close(local_fd) == -1) {
error("Couldn't close local file \"%s\": %s", local_path,
strerror(errno));
do_close(fd_in, fd_out, handle, handle_len);
status = -1;
goto done;
}
/* Override umask and utimes if asked */
if (pflag)
do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
status = do_close(fd_in, fd_out, handle, handle_len);
done:
xfree(handle);
buffer_free(&msg);
return status;
}

View File

@ -0,0 +1,107 @@
/* $OpenBSD: sftp-client.h,v 1.5 2001/04/05 10:42:52 markus Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Client side of SSH2 filexfer protocol */
typedef struct SFTP_DIRENT SFTP_DIRENT;
struct SFTP_DIRENT {
char *filename;
char *longname;
Attrib a;
};
/*
* Initialiase a SSH filexfer connection. Returns -1 on error or
* protocol version on success.
*/
int do_init(int fd_in, int fd_out);
/* Close file referred to by 'handle' */
int do_close(int fd_in, int fd_out, char *handle, u_int handle_len);
/* List contents of directory 'path' to stdout */
int do_ls(int fd_in, int fd_out, char *path);
/* Read contents of 'path' to NULL-terminated array 'dir' */
int do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir);
/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */
void free_sftp_dirents(SFTP_DIRENT **s);
/* Delete file 'path' */
int do_rm(int fd_in, int fd_out, char *path);
/* Create directory 'path' */
int do_mkdir(int fd_in, int fd_out, char *path, Attrib *a);
/* Remove directory 'path' */
int do_rmdir(int fd_in, int fd_out, char *path);
/* Get file attributes of 'path' (follows symlinks) */
Attrib *do_stat(int fd_in, int fd_out, char *path, int quiet);
/* Get file attributes of 'path' (does not follow symlinks) */
Attrib *do_lstat(int fd_in, int fd_out, char *path, int quiet);
/* Get file attributes of open file 'handle' */
Attrib *do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len,
int quiet);
/* Set file attributes of 'path' */
int do_setstat(int fd_in, int fd_out, char *path, Attrib *a);
/* Set file attributes of open file 'handle' */
int do_fsetstat(int fd_in, int fd_out, char *handle,
u_int handle_len, Attrib *a);
/* Canonicalise 'path' - caller must free result */
char *do_realpath(int fd_in, int fd_out, char *path);
/* Rename 'oldpath' to 'newpath' */
int do_rename(int fd_in, int fd_out, char *oldpath, char *newpath);
/* Rename 'oldpath' to 'newpath' */
int do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath);
/* Return target of symlink 'path' - caller must free result */
char *do_readlink(int fd_in, int fd_out, char *path);
/* XXX: add callbacks to do_download/do_upload so we can do progress meter */
/*
* Download 'remote_path' to 'local_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
int pflag);
/*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
int pflag);

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-common.c,v 1.2 2001/02/06 23:50:10 markus Exp $");
#include "buffer.h"
#include "bufaux.h"
#include "getput.h"
#include "log.h"
#include "xmalloc.h"
#include "sftp.h"
#include "sftp-common.h"
void
attrib_clear(Attrib *a)
{
a->flags = 0;
a->size = 0;
a->uid = 0;
a->gid = 0;
a->perm = 0;
a->atime = 0;
a->mtime = 0;
}
void
stat_to_attrib(struct stat *st, Attrib *a)
{
attrib_clear(a);
a->flags = 0;
a->flags |= SSH2_FILEXFER_ATTR_SIZE;
a->size = st->st_size;
a->flags |= SSH2_FILEXFER_ATTR_UIDGID;
a->uid = st->st_uid;
a->gid = st->st_gid;
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a->perm = st->st_mode;
a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME;
a->atime = st->st_atime;
a->mtime = st->st_mtime;
}
Attrib *
decode_attrib(Buffer *b)
{
static Attrib a;
attrib_clear(&a);
a.flags = buffer_get_int(b);
if (a.flags & SSH2_FILEXFER_ATTR_SIZE)
a.size = buffer_get_int64(b);
if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
a.uid = buffer_get_int(b);
a.gid = buffer_get_int(b);
}
if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
a.perm = buffer_get_int(b);
if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
a.atime = buffer_get_int(b);
a.mtime = buffer_get_int(b);
}
/* vendor-specific extensions */
if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) {
char *type, *data;
int i, count;
count = buffer_get_int(b);
for (i = 0; i < count; i++) {
type = buffer_get_string(b, NULL);
data = buffer_get_string(b, NULL);
debug3("Got file attribute \"%s\"", type);
xfree(type);
xfree(data);
}
}
return &a;
}
void
encode_attrib(Buffer *b, Attrib *a)
{
buffer_put_int(b, a->flags);
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
buffer_put_int64(b, a->size);
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
buffer_put_int(b, a->uid);
buffer_put_int(b, a->gid);
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
buffer_put_int(b, a->perm);
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
buffer_put_int(b, a->atime);
buffer_put_int(b, a->mtime);
}
}
const char *
fx2txt(int status)
{
switch (status) {
case SSH2_FX_OK:
return("No error");
case SSH2_FX_EOF:
return("End of file");
case SSH2_FX_NO_SUCH_FILE:
return("No such file or directory");
case SSH2_FX_PERMISSION_DENIED:
return("Permission denied");
case SSH2_FX_FAILURE:
return("Failure");
case SSH2_FX_BAD_MESSAGE:
return("Bad message");
case SSH2_FX_NO_CONNECTION:
return("No connection");
case SSH2_FX_CONNECTION_LOST:
return("Connection lost");
case SSH2_FX_OP_UNSUPPORTED:
return("Operation unsupported");
default:
return("Unknown status");
};
/* NOTREACHED */
}

View File

@ -0,0 +1,55 @@
/* $OpenBSD: sftp-common.h,v 1.1 2001/02/04 11:11:54 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
typedef struct Attrib Attrib;
/* File attributes */
struct Attrib {
u_int32_t flags;
u_int64_t size;
u_int32_t uid;
u_int32_t gid;
u_int32_t perm;
u_int32_t atime;
u_int32_t mtime;
};
/* Clear contents of attributes structure */
void attrib_clear(Attrib *a);
/* Convert from struct stat to filexfer attribs */
void stat_to_attrib(struct stat *st, Attrib *a);
/* Decode attributes in buffer */
Attrib *decode_attrib(Buffer *b);
/* Encode attributes to buffer */
void encode_attrib(Buffer *b, Attrib *a);
/* Convert from SSH2_FX_ status to text error message */
const char *fx2txt(int status);

146
crypto/openssh/sftp-glob.c Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-glob.c,v 1.5 2001/04/15 08:43:46 markus Exp $");
#include <glob.h>
#include "ssh.h"
#include "buffer.h"
#include "bufaux.h"
#include "getput.h"
#include "xmalloc.h"
#include "log.h"
#include "atomicio.h"
#include "pathnames.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
#include "sftp-glob.h"
struct SFTP_OPENDIR {
SFTP_DIRENT **dir;
int offset;
};
static struct {
int fd_in;
int fd_out;
} cur;
void *fudge_opendir(const char *path)
{
struct SFTP_OPENDIR *r;
r = xmalloc(sizeof(*r));
if (do_readdir(cur.fd_in, cur.fd_out, (char*)path, &r->dir))
return(NULL);
r->offset = 0;
return((void*)r);
}
struct dirent *fudge_readdir(struct SFTP_OPENDIR *od)
{
static struct dirent ret;
if (od->dir[od->offset] == NULL)
return(NULL);
memset(&ret, 0, sizeof(ret));
strlcpy(ret.d_name, od->dir[od->offset++]->filename,
sizeof(ret.d_name));
return(&ret);
}
void fudge_closedir(struct SFTP_OPENDIR *od)
{
free_sftp_dirents(od->dir);
xfree(od);
}
void attrib_to_stat(Attrib *a, struct stat *st)
{
memset(st, 0, sizeof(*st));
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
st->st_size = a->size;
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
st->st_uid = a->uid;
st->st_gid = a->gid;
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
st->st_mode = a->perm;
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
st->st_atime = a->atime;
st->st_mtime = a->mtime;
}
}
int fudge_lstat(const char *path, struct stat *st)
{
Attrib *a;
if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path, 0)))
return(-1);
attrib_to_stat(a, st);
return(0);
}
int fudge_stat(const char *path, struct stat *st)
{
Attrib *a;
if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path, 0)))
return(-1);
attrib_to_stat(a, st);
return(0);
}
int
remote_glob(int fd_in, int fd_out, const char *pattern, int flags,
int (*errfunc)(const char *, int), glob_t *pglob)
{
pglob->gl_opendir = (void*)fudge_opendir;
pglob->gl_readdir = (void*)fudge_readdir;
pglob->gl_closedir = (void*)fudge_closedir;
pglob->gl_lstat = fudge_lstat;
pglob->gl_stat = fudge_stat;
memset(&cur, 0, sizeof(cur));
cur.fd_in = fd_in;
cur.fd_out = fd_out;
return(glob(pattern, flags | GLOB_ALTDIRFUNC, (void*)errfunc,
pglob));
}

View File

@ -0,0 +1,32 @@
/* $OpenBSD: sftp-glob.h,v 1.3 2001/04/15 08:43:46 markus Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Remote sftp filename globbing */
int
remote_glob(int fd_in, int fd_out, const char *pattern, int flags,
int (*errfunc)(const char *, int), glob_t *pglob);

917
crypto/openssh/sftp-int.c Normal file
View File

@ -0,0 +1,917 @@
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* XXX: globbed ls */
/* XXX: recursive operations */
#include "includes.h"
RCSID("$OpenBSD: sftp-int.c,v 1.36 2001/04/15 08:43:46 markus Exp $");
#include <glob.h>
#include "buffer.h"
#include "xmalloc.h"
#include "log.h"
#include "pathnames.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-glob.h"
#include "sftp-client.h"
#include "sftp-int.h"
/* File to read commands from */
extern FILE *infile;
/* Version of server we are speaking to */
int version;
/* Seperators for interactive commands */
#define WHITESPACE " \t\r\n"
/* Commands for interactive mode */
#define I_CHDIR 1
#define I_CHGRP 2
#define I_CHMOD 3
#define I_CHOWN 4
#define I_GET 5
#define I_HELP 6
#define I_LCHDIR 7
#define I_LLS 8
#define I_LMKDIR 9
#define I_LPWD 10
#define I_LS 11
#define I_LUMASK 12
#define I_MKDIR 13
#define I_PUT 14
#define I_PWD 15
#define I_QUIT 16
#define I_RENAME 17
#define I_RM 18
#define I_RMDIR 19
#define I_SHELL 20
#define I_SYMLINK 21
#define I_VERSION 22
struct CMD {
const char *c;
const int n;
};
const struct CMD cmds[] = {
{ "cd", I_CHDIR },
{ "chdir", I_CHDIR },
{ "chgrp", I_CHGRP },
{ "chmod", I_CHMOD },
{ "chown", I_CHOWN },
{ "dir", I_LS },
{ "exit", I_QUIT },
{ "get", I_GET },
{ "mget", I_GET },
{ "help", I_HELP },
{ "lcd", I_LCHDIR },
{ "lchdir", I_LCHDIR },
{ "lls", I_LLS },
{ "lmkdir", I_LMKDIR },
{ "ln", I_SYMLINK },
{ "lpwd", I_LPWD },
{ "ls", I_LS },
{ "lumask", I_LUMASK },
{ "mkdir", I_MKDIR },
{ "put", I_PUT },
{ "mput", I_PUT },
{ "pwd", I_PWD },
{ "quit", I_QUIT },
{ "rename", I_RENAME },
{ "rm", I_RM },
{ "rmdir", I_RMDIR },
{ "symlink", I_SYMLINK },
{ "version", I_VERSION },
{ "!", I_SHELL },
{ "?", I_HELP },
{ NULL, -1}
};
void
help(void)
{
printf("Available commands:\n");
printf("cd path Change remote directory to 'path'\n");
printf("lcd path Change local directory to 'path'\n");
printf("chgrp grp path Change group of file 'path' to 'grp'\n");
printf("chmod mode path Change permissions of file 'path' to 'mode'\n");
printf("chown own path Change owner of file 'path' to 'own'\n");
printf("help Display this help text\n");
printf("get remote-path [local-path] Download file\n");
printf("lls [ls-options [path]] Display local directory listing\n");
printf("ln oldpath newpath Symlink remote file\n");
printf("lmkdir path Create local directory\n");
printf("lpwd Print local working directory\n");
printf("ls [path] Display remote directory listing\n");
printf("lumask umask Set local umask to 'umask'\n");
printf("mkdir path Create remote directory\n");
printf("put local-path [remote-path] Upload file\n");
printf("pwd Display remote working directory\n");
printf("exit Quit sftp\n");
printf("quit Quit sftp\n");
printf("rename oldpath newpath Rename remote file\n");
printf("rmdir path Remove remote directory\n");
printf("rm path Delete remote file\n");
printf("symlink oldpath newpath Symlink remote file\n");
printf("version Show SFTP version\n");
printf("!command Execute 'command' in local shell\n");
printf("! Escape to local shell\n");
printf("? Synonym for help\n");
}
void
local_do_shell(const char *args)
{
int status;
char *shell;
pid_t pid;
if (!*args)
args = NULL;
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
if ((pid = fork()) == -1)
fatal("Couldn't fork: %s", strerror(errno));
if (pid == 0) {
/* XXX: child has pipe fds to ssh subproc open - issue? */
if (args) {
debug3("Executing %s -c \"%s\"", shell, args);
execl(shell, shell, "-c", args, NULL);
} else {
debug3("Executing %s", shell);
execl(shell, shell, NULL);
}
fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
strerror(errno));
_exit(1);
}
if (waitpid(pid, &status, 0) == -1)
fatal("Couldn't wait for child: %s", strerror(errno));
if (!WIFEXITED(status))
error("Shell exited abormally");
else if (WEXITSTATUS(status))
error("Shell exited with status %d", WEXITSTATUS(status));
}
void
local_do_ls(const char *args)
{
if (!args || !*args)
local_do_shell(_PATH_LS);
else {
int len = strlen(_PATH_LS " ") + strlen(args) + 1;
char *buf = xmalloc(len);
/* XXX: quoting - rip quoting code from ftp? */
snprintf(buf, len, _PATH_LS " %s", args);
local_do_shell(buf);
xfree(buf);
}
}
char *
path_append(char *p1, char *p2)
{
char *ret;
int len = strlen(p1) + strlen(p2) + 2;
ret = xmalloc(len);
strlcpy(ret, p1, len);
strlcat(ret, "/", len);
strlcat(ret, p2, len);
return(ret);
}
char *
make_absolute(char *p, char *pwd)
{
char *abs;
/* Derelativise */
if (p && p[0] != '/') {
abs = path_append(pwd, p);
xfree(p);
return(abs);
} else
return(p);
}
int
infer_path(const char *p, char **ifp)
{
char *cp;
cp = strrchr(p, '/');
if (cp == NULL) {
*ifp = xstrdup(p);
return(0);
}
if (!cp[1]) {
error("Invalid path");
return(-1);
}
*ifp = xstrdup(cp + 1);
return(0);
}
int
parse_getput_flags(const char **cpp, int *pflag)
{
const char *cp = *cpp;
/* Check for flags */
if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) {
switch (cp[1]) {
case 'p':
case 'P':
*pflag = 1;
break;
default:
error("Invalid flag -%c", cp[1]);
return(-1);
}
cp += 2;
*cpp = cp + strspn(cp, WHITESPACE);
}
return(0);
}
int
get_pathname(const char **cpp, char **path)
{
const char *cp = *cpp, *end;
char quot;
int i;
cp += strspn(cp, WHITESPACE);
if (!*cp) {
*cpp = cp;
*path = NULL;
return (0);
}
/* Check for quoted filenames */
if (*cp == '\"' || *cp == '\'') {
quot = *cp++;
end = strchr(cp, quot);
if (end == NULL) {
error("Unterminated quote");
goto fail;
}
if (cp == end) {
error("Empty quotes");
goto fail;
}
*cpp = end + 1 + strspn(end + 1, WHITESPACE);
} else {
/* Read to end of filename */
end = strpbrk(cp, WHITESPACE);
if (end == NULL)
end = strchr(cp, '\0');
*cpp = end + strspn(end, WHITESPACE);
}
i = end - cp;
*path = xmalloc(i + 1);
memcpy(*path, cp, i);
(*path)[i] = '\0';
return(0);
fail:
*path = NULL;
return (-1);
}
int
is_dir(char *path)
{
struct stat sb;
/* XXX: report errors? */
if (stat(path, &sb) == -1)
return(0);
return(sb.st_mode & S_IFDIR);
}
int
remote_is_dir(int in, int out, char *path)
{
Attrib *a;
/* XXX: report errors? */
if ((a = do_stat(in, out, path, 1)) == NULL)
return(0);
if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
return(0);
return(a->perm & S_IFDIR);
}
int
process_get(int in, int out, char *src, char *dst, char *pwd, int pflag)
{
char *abs_src = NULL;
char *abs_dst = NULL;
char *tmp;
glob_t g;
int err = 0;
int i;
abs_src = xstrdup(src);
abs_src = make_absolute(abs_src, pwd);
memset(&g, 0, sizeof(g));
debug3("Looking up %s", abs_src);
if (remote_glob(in, out, abs_src, 0, NULL, &g)) {
error("File \"%s\" not found.", abs_src);
err = -1;
goto out;
}
/* Only one match, dst may be file, directory or unspecified */
if (g.gl_pathv[0] && g.gl_matchc == 1) {
if (dst) {
/* If directory specified, append filename */
if (is_dir(dst)) {
if (infer_path(g.gl_pathv[0], &tmp)) {
err = 1;
goto out;
}
abs_dst = path_append(dst, tmp);
xfree(tmp);
} else
abs_dst = xstrdup(dst);
} else if (infer_path(g.gl_pathv[0], &abs_dst)) {
err = -1;
goto out;
}
printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
goto out;
}
/* Multiple matches, dst may be directory or unspecified */
if (dst && !is_dir(dst)) {
error("Multiple files match, but \"%s\" is not a directory",
dst);
err = -1;
goto out;
}
for(i = 0; g.gl_pathv[i]; i++) {
if (infer_path(g.gl_pathv[i], &tmp)) {
err = -1;
goto out;
}
if (dst) {
abs_dst = path_append(dst, tmp);
xfree(tmp);
} else
abs_dst = tmp;
printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
err = -1;
xfree(abs_dst);
abs_dst = NULL;
}
out:
xfree(abs_src);
if (abs_dst)
xfree(abs_dst);
globfree(&g);
return(err);
}
int
process_put(int in, int out, char *src, char *dst, char *pwd, int pflag)
{
char *tmp_dst = NULL;
char *abs_dst = NULL;
char *tmp;
glob_t g;
int err = 0;
int i;
if (dst) {
tmp_dst = xstrdup(dst);
tmp_dst = make_absolute(tmp_dst, pwd);
}
memset(&g, 0, sizeof(g));
debug3("Looking up %s", src);
if (glob(src, 0, NULL, &g)) {
error("File \"%s\" not found.", src);
err = -1;
goto out;
}
/* Only one match, dst may be file, directory or unspecified */
if (g.gl_pathv[0] && g.gl_matchc == 1) {
if (tmp_dst) {
/* If directory specified, append filename */
if (remote_is_dir(in, out, tmp_dst)) {
if (infer_path(g.gl_pathv[0], &tmp)) {
err = 1;
goto out;
}
abs_dst = path_append(tmp_dst, tmp);
xfree(tmp);
} else
abs_dst = xstrdup(tmp_dst);
} else {
if (infer_path(g.gl_pathv[0], &abs_dst)) {
err = -1;
goto out;
}
abs_dst = make_absolute(abs_dst, pwd);
}
printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
goto out;
}
/* Multiple matches, dst may be directory or unspecified */
if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) {
error("Multiple files match, but \"%s\" is not a directory",
tmp_dst);
err = -1;
goto out;
}
for(i = 0; g.gl_pathv[i]; i++) {
if (infer_path(g.gl_pathv[i], &tmp)) {
err = -1;
goto out;
}
if (tmp_dst) {
abs_dst = path_append(tmp_dst, tmp);
xfree(tmp);
} else
abs_dst = make_absolute(tmp, pwd);
printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
err = -1;
}
out:
if (abs_dst)
xfree(abs_dst);
if (tmp_dst)
xfree(tmp_dst);
return(err);
}
int
parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
char **path1, char **path2)
{
const char *cmd, *cp = *cpp;
char *cp2;
int base = 0;
long l;
int i, cmdnum;
/* Skip leading whitespace */
cp = cp + strspn(cp, WHITESPACE);
/* Ignore blank lines */
if (!*cp)
return(-1);
/* Figure out which command we have */
for(i = 0; cmds[i].c; i++) {
int cmdlen = strlen(cmds[i].c);
/* Check for command followed by whitespace */
if (!strncasecmp(cp, cmds[i].c, cmdlen) &&
strchr(WHITESPACE, cp[cmdlen])) {
cp += cmdlen;
cp = cp + strspn(cp, WHITESPACE);
break;
}
}
cmdnum = cmds[i].n;
cmd = cmds[i].c;
/* Special case */
if (*cp == '!') {
cp++;
cmdnum = I_SHELL;
} else if (cmdnum == -1) {
error("Invalid command.");
return(-1);
}
/* Get arguments and parse flags */
*pflag = *n_arg = 0;
*path1 = *path2 = NULL;
switch (cmdnum) {
case I_GET:
case I_PUT:
if (parse_getput_flags(&cp, pflag))
return(-1);
/* Get first pathname (mandatory) */
if (get_pathname(&cp, path1))
return(-1);
if (*path1 == NULL) {
error("You must specify at least one path after a "
"%s command.", cmd);
return(-1);
}
/* Try to get second pathname (optional) */
if (get_pathname(&cp, path2))
return(-1);
break;
case I_RENAME:
case I_SYMLINK:
if (get_pathname(&cp, path1))
return(-1);
if (get_pathname(&cp, path2))
return(-1);
if (!*path1 || !*path2) {
error("You must specify two paths after a %s "
"command.", cmd);
return(-1);
}
break;
case I_RM:
case I_MKDIR:
case I_RMDIR:
case I_CHDIR:
case I_LCHDIR:
case I_LMKDIR:
/* Get pathname (mandatory) */
if (get_pathname(&cp, path1))
return(-1);
if (*path1 == NULL) {
error("You must specify a path after a %s command.",
cmd);
return(-1);
}
break;
case I_LS:
/* Path is optional */
if (get_pathname(&cp, path1))
return(-1);
break;
case I_LLS:
case I_SHELL:
/* Uses the rest of the line */
break;
case I_LUMASK:
base = 8;
case I_CHMOD:
base = 8;
case I_CHOWN:
case I_CHGRP:
/* Get numeric arg (mandatory) */
l = strtol(cp, &cp2, base);
if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) &&
errno == ERANGE) || l < 0) {
error("You must supply a numeric argument "
"to the %s command.", cmd);
return(-1);
}
cp = cp2;
*n_arg = l;
if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp))
break;
if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) {
error("You must supply a numeric argument "
"to the %s command.", cmd);
return(-1);
}
cp += strspn(cp, WHITESPACE);
/* Get pathname (mandatory) */
if (get_pathname(&cp, path1))
return(-1);
if (*path1 == NULL) {
error("You must specify a path after a %s command.",
cmd);
return(-1);
}
break;
case I_QUIT:
case I_PWD:
case I_LPWD:
case I_HELP:
case I_VERSION:
break;
default:
fatal("Command not implemented");
}
*cpp = cp;
return(cmdnum);
}
int
parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
{
char *path1, *path2, *tmp;
int pflag, cmdnum, i;
unsigned long n_arg;
Attrib a, *aa;
char path_buf[MAXPATHLEN];
int err = 0;
glob_t g;
path1 = path2 = NULL;
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
memset(&g, 0, sizeof(g));
/* Perform command */
switch (cmdnum) {
case -1:
break;
case I_GET:
err = process_get(in, out, path1, path2, *pwd, pflag);
break;
case I_PUT:
err = process_put(in, out, path1, path2, *pwd, pflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_rename(in, out, path1, path2);
break;
case I_SYMLINK:
if (version < 3) {
error("The server (version %d) does not support "
"this operation", version);
err = -1;
} else {
path2 = make_absolute(path2, *pwd);
err = do_symlink(in, out, path1, path2);
}
break;
case I_RM:
path1 = make_absolute(path1, *pwd);
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
printf("Removing %s\n", g.gl_pathv[i]);
if (do_rm(in, out, g.gl_pathv[i]) == -1)
err = -1;
}
break;
case I_MKDIR:
path1 = make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777;
err = do_mkdir(in, out, path1, &a);
break;
case I_RMDIR:
path1 = make_absolute(path1, *pwd);
err = do_rmdir(in, out, path1);
break;
case I_CHDIR:
path1 = make_absolute(path1, *pwd);
if ((tmp = do_realpath(in, out, path1)) == NULL) {
err = 1;
break;
}
if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
xfree(tmp);
err = 1;
break;
}
if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
error("Can't change directory: Can't check target");
xfree(tmp);
err = 1;
break;
}
if (!S_ISDIR(aa->perm)) {
error("Can't change directory: \"%s\" is not "
"a directory", tmp);
xfree(tmp);
err = 1;
break;
}
xfree(*pwd);
*pwd = tmp;
break;
case I_LS:
if (!path1) {
do_ls(in, out, *pwd);
break;
}
path1 = make_absolute(path1, *pwd);
if ((tmp = do_realpath(in, out, path1)) == NULL)
break;
xfree(path1);
path1 = tmp;
if ((aa = do_stat(in, out, path1, 0)) == NULL)
break;
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
!S_ISDIR(aa->perm)) {
error("Can't ls: \"%s\" is not a directory", path1);
break;
}
do_ls(in, out, path1);
break;
case I_LCHDIR:
if (chdir(path1) == -1) {
error("Couldn't change local directory to "
"\"%s\": %s", path1, strerror(errno));
err = 1;
}
break;
case I_LMKDIR:
if (mkdir(path1, 0777) == -1) {
error("Couldn't create local directory "
"\"%s\": %s", path1, strerror(errno));
err = 1;
}
break;
case I_LLS:
local_do_ls(cmd);
break;
case I_SHELL:
local_do_shell(cmd);
break;
case I_LUMASK:
umask(n_arg);
printf("Local umask: %03lo\n", n_arg);
break;
case I_CHMOD:
path1 = make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = n_arg;
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
printf("Changing mode on %s\n", g.gl_pathv[i]);
do_setstat(in, out, g.gl_pathv[i], &a);
}
break;
case I_CHOWN:
path1 = make_absolute(path1, *pwd);
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
continue;
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
"remote file \"%s\"", g.gl_pathv[i]);
continue;
}
printf("Changing owner on %s\n", g.gl_pathv[i]);
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
aa->uid = n_arg;
do_setstat(in, out, g.gl_pathv[i], aa);
}
break;
case I_CHGRP:
path1 = make_absolute(path1, *pwd);
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
continue;
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
"remote file \"%s\"", g.gl_pathv[i]);
continue;
}
printf("Changing group on %s\n", g.gl_pathv[i]);
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
aa->gid = n_arg;
do_setstat(in, out, g.gl_pathv[i], aa);
}
break;
case I_PWD:
printf("Remote working directory: %s\n", *pwd);
break;
case I_LPWD:
if (!getcwd(path_buf, sizeof(path_buf)))
error("Couldn't get local cwd: %s",
strerror(errno));
else
printf("Local working directory: %s\n",
path_buf);
break;
case I_QUIT:
return(-1);
case I_HELP:
help();
break;
case I_VERSION:
printf("SFTP protocol version %d\n", version);
break;
default:
fatal("%d is not implemented", cmdnum);
}
if (g.gl_pathc)
globfree(&g);
if (path1)
xfree(path1);
if (path2)
xfree(path2);
/* If an error occurs in batch mode we should abort. */
if (infile != stdin && err > 0)
return -1;
return(0);
}
void
interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
{
char *pwd;
char *dir = NULL;
char cmd[2048];
version = do_init(fd_in, fd_out);
if (version == -1)
fatal("Couldn't initialise connection to server");
pwd = do_realpath(fd_in, fd_out, ".");
if (pwd == NULL)
fatal("Need cwd");
if (file1 != NULL) {
dir = xstrdup(file1);
dir = make_absolute(dir, pwd);
if (remote_is_dir(fd_in, fd_out, dir) && file2 == NULL) {
printf("Changing to: %s\n", dir);
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
} else {
if (file2 == NULL)
snprintf(cmd, sizeof cmd, "get %s", dir);
else
snprintf(cmd, sizeof cmd, "get %s %s", dir,
file2);
parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
return;
}
}
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(infile, NULL, _IOLBF, 0);
for(;;) {
char *cp;
printf("sftp> ");
/* XXX: use libedit */
if (fgets(cmd, sizeof(cmd), infile) == NULL) {
printf("\n");
break;
} else if (infile != stdin) /* Bluff typing */
printf("%s", cmd);
cp = strrchr(cmd, '\n');
if (cp)
*cp = '\0';
if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd))
break;
}
xfree(pwd);
}

27
crypto/openssh/sftp-int.h Normal file
View File

@ -0,0 +1,27 @@
/* $OpenBSD: sftp-int.h,v 1.2 2001/04/12 23:17:54 mouring Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void interactive_loop(int fd_in, int fd_out, char *file1, char *file2);

View File

@ -1,6 +1,6 @@
.\" $OpenBSD: sftp-server.8,v 1.3 2000/10/13 17:20:44 aaron Exp $
.\" $OpenBSD: sftp-server.8,v 1.6 2001/04/22 13:32:26 markus Exp $
.\"
.\" Copyright (c) 2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 2000 Markus Friedl. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -44,11 +44,18 @@ See
.Xr sshd 8
for more information.
.Sh SEE ALSO
.Xr sftp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-keygen 1 ,
.Xr sshd 8
.Sh AUTHOR
.Rs
.%A T. Ylonen
.%A S. Lehtinen
.%T "SSH File Transfer Protocol"
.%N draft-ietf-secsh-filexfer-00.txt
.%D January 2001
.%O work in progress material
.Re
.Sh AUTHORS
Markus Friedl <markus@openbsd.org>
.Sh HISTORY
.Nm

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.5 2001/03/03 23:59:36 markus Exp $
.PATH: ${.CURDIR}/..
PROG= sftp-server
@ -8,9 +10,9 @@ BINMODE?=555
BINDIR= /usr/libexec
MAN= sftp-server.8
SRCS= sftp-server.c log-server.c
SRCS= sftp-server.c sftp-common.c
.include <bsd.prog.mk>
LDADD+= -lcrypto # -lutil -lz
DPADD+= ${LIBCRYPTO} # ${LIBDES} ${LIBUTIL} ${LIBZ}
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}

222
crypto/openssh/sftp.1 Normal file
View File

@ -0,0 +1,222 @@
.\" $OpenBSD: sftp.1,v 1.17 2001/04/22 13:32:27 markus Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd February 4, 2001
.Dt SFTP 1
.Os
.Sh NAME
.Nm sftp
.Nd Secure file transfer program
.Sh SYNOPSIS
.Nm sftp
.Op Fl vC
.Op Fl b Ar batchfile
.Op Fl o Ar ssh_option
.Op Ar host
.Nm sftp
.Op [\fIuser\fR@]\fIhost\fR[:\fIfile\fR [\fIfile\fR]]
.Nm sftp
.Op [\fIuser\fR@]\fIhost\fR[:\fIdir\fR[\fI/\fR]]
.Sh DESCRIPTION
.Nm
is an interactive file transfer program, similar to
.Xr ftp 1 ,
which performs all operations over an encrypted
.Xr ssh 1
transport.
It may also use many features of ssh, such as public key authentication and
compression.
.Nm
connects and logs into the specified
.Ar hostname ,
then enters an interactive command mode.
.Pp
The second usage format will fetch files automaticly if a non-interactive
authentication is used, else it do so after an interactive authentication
is used.
.Pp
The last usage format allows the sftp client to start in a remote directory.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl b Ar batchfile
Batch mode reads a series of commands from an input
.Ar batchfile
instead of
.Em stdin .
Since it lacks user interaction it should be used in conjunction with
non-interactive authentication.
.Nm
will abort if any of the following
commands fail:
.Ic get , put , rename , ln , rm , mkdir , chdir , lchdir
and
.Ic lmkdir .
.It Fl C
Enables compression (via ssh's
.Fl C
flag)
.It Fl o Ar ssh_option
Specify an option to be directly passed to
.Xr ssh 1 .
.It Fl v
Raise logging level. This option is also passed to ssh.
.El
.Sh INTERACTIVE COMMANDS
Once in interactive mode,
.Nm
understands a set of commands similar to those of
.Xr ftp 1 .
Commands are case insensitive and pathnames may be enclosed in quotes if they
contain spaces.
.Bl -tag -width Ds
.It Ic cd Ar path
Change remote directory to
.Ar path .
.It Ic lcd Ar path
Change local directory to
.Ar path .
.It Ic chgrp Ar grp Ar path
Change group of file
.Ar path
to
.Ar grp .
.Ar grp
must be a numeric GID.
.It Ic chmod Ar mode Ar path
Change permissions of file
.Ar path
to
.Ar mode .
.It Ic chown Ar own Ar path
Change owner of file
.Ar path
to
.Ar own .
.Ar own
must be a numeric UID.
.It Ic exit
Quit sftp.
.It Xo Ic get
.Op Ar flags
.Ar remote-path
.Op Ar local-path
.Xc
Retrieve the
.Ar remote-path
and store it on the local machine.
If the local
path name is not specified, it is given the same name it has on the
remote machine. If the
.Fl P
flag is specified, then the file's full permission and access time are
copied too.
.It Ic help
Display help text.
.It Ic lls Op Ar ls-options Op Ar path
Display local directory listing of either
.Ar path
or current directory if
.Ar path
is not specified.
.It Ic lmkdir Ar path
Create local directory specified by
.Ar path .
.It Ic ln Ar oldpath Ar newpath
Create a symbolic link from
.Ar oldpath
to
.Ar newpath .
.It Ic lpwd
Print local working directory.
.It Ic ls Op Ar path
Display remote directory listing of either
.Ar path
or current directory if
.Ar path
is not specified.
.It Ic lumask Ar umask
Set local umask to
.Ar umask .
.It Ic mkdir Ar path
Create remote directory specified by
.Ar path .
.It Xo Ic put
.Op Ar flags
.Ar local-path
.Op Ar local-path
.Xc
Upload
.Ar local-path
and store it on the remote machine. If the remote path name is not
specified, it is given the same name it has on the local machine. If the
.Fl P
flag is specified, then the file's full permission and access time are
copied too.
.It Ic pwd
Display remote working directory.
.It Ic quit
Quit sftp.
.It Ic rename Ar oldpath Ar newpath
Rename remote file from
.Ar oldpath
to
.Ar newpath .
.It Ic rmdir Ar path
Remove remote directory specified by
.Ar path .
.It Ic rm Ar path
Delete remote file specified by
.Ar path .
.It Ic symlink Ar oldpath Ar newpath
Create a symbolic link from
.Ar oldpath
to
.Ar newpath .
.It Ic ! Ar command
Execute
.Ar command
in local shell.
.It Ic !
Escape to local shell.
.It Ic ?
Synonym for help.
.El
.Sh AUTHORS
Damien Miller <djm@mindrot.org>
.Sh SEE ALSO
.Xr scp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-keygen 1 ,
.Xr sftp-server 8 ,
.Xr sshd 8
.Rs
.%A T. Ylonen
.%A S. Lehtinen
.%T "SSH File Transfer Protocol"
.%N draft-ietf-secsh-filexfer-00.txt
.%D January 2001
.%O work in progress material
.Re

271
crypto/openssh/sftp.c Normal file
View File

@ -0,0 +1,271 @@
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sftp.c,v 1.15 2001/04/16 02:31:44 mouring Exp $");
/* XXX: commandline mode */
/* XXX: short-form remote directory listings (like 'ls -C') */
#include "buffer.h"
#include "xmalloc.h"
#include "log.h"
#include "pathnames.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
#include "sftp-int.h"
#include "scp-common.h"
int use_ssh1 = 0;
char *ssh_program = _PATH_SSH_PROGRAM;
char *sftp_server = NULL;
FILE* infile;
void
connect_to_server(char **args, int *in, int *out, pid_t *sshpid)
{
int c_in, c_out;
#ifdef USE_PIPES
int pin[2], pout[2];
if ((pipe(pin) == -1) || (pipe(pout) == -1))
fatal("pipe: %s", strerror(errno));
*in = pin[0];
*out = pout[1];
c_in = pout[0];
c_out = pin[1];
#else /* USE_PIPES */
int inout[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
fatal("socketpair: %s", strerror(errno));
*in = *out = inout[0];
c_in = c_out = inout[1];
#endif /* USE_PIPES */
if ((*sshpid = fork()) == -1)
fatal("fork: %s", strerror(errno));
else if (*sshpid == 0) {
if ((dup2(c_in, STDIN_FILENO) == -1) ||
(dup2(c_out, STDOUT_FILENO) == -1)) {
fprintf(stderr, "dup2: %s\n", strerror(errno));
exit(1);
}
close(*in);
close(*out);
close(c_in);
close(c_out);
execv(ssh_program, args);
fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno));
exit(1);
}
close(c_in);
close(c_out);
}
char **
make_ssh_args(char *add_arg)
{
static char **args = NULL;
static int nargs = 0;
char debug_buf[4096];
int i;
/* Init args array */
if (args == NULL) {
nargs = 2;
i = 0;
args = xmalloc(sizeof(*args) * nargs);
args[i++] = "ssh";
args[i++] = NULL;
}
/* If asked to add args, then do so and return */
if (add_arg) {
i = nargs++ - 1;
args = xrealloc(args, sizeof(*args) * nargs);
args[i++] = add_arg;
args[i++] = NULL;
return(NULL);
}
/* no subsystem if the server-spec contains a '/' */
if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
make_ssh_args("-s");
make_ssh_args("-oForwardX11=no");
make_ssh_args("-oForwardAgent=no");
make_ssh_args(use_ssh1 ? "-oProtocol=1" : "-oProtocol=2");
/* Otherwise finish up and return the arg array */
if (sftp_server != NULL)
make_ssh_args(sftp_server);
else
make_ssh_args("sftp");
/* XXX: overflow - doesn't grow debug_buf */
debug_buf[0] = '\0';
for(i = 0; args[i]; i++) {
if (i)
strlcat(debug_buf, " ", sizeof(debug_buf));
strlcat(debug_buf, args[i], sizeof(debug_buf));
}
debug("SSH args \"%s\"", debug_buf);
return(args);
}
void
usage(void)
{
fprintf(stderr, "usage: sftp [-1vC] [-b batchfile] [-osshopt=value] [user@]host[:file [file]]\n");
exit(1);
}
int
main(int argc, char **argv)
{
int in, out, ch, debug_level, compress_flag;
pid_t sshpid;
char *file1 = NULL;
char *host, *userhost, *cp, *file2;
LogLevel ll;
extern int optind;
extern char *optarg;
infile = stdin; /* Read from STDIN unless changed by -b */
debug_level = compress_flag = 0;
while ((ch = getopt(argc, argv, "1hvCo:s:S:b:")) != -1) {
switch (ch) {
case 'C':
compress_flag = 1;
break;
case 'v':
debug_level = MIN(3, debug_level + 1);
break;
case 'o':
make_ssh_args("-o");
make_ssh_args(optarg);
break;
case '1':
use_ssh1 = 1;
if (sftp_server == NULL)
sftp_server = _PATH_SFTP_SERVER;
break;
case 's':
sftp_server = optarg;
break;
case 'S':
ssh_program = optarg;
break;
case 'b':
if (infile == stdin) {
infile = fopen(optarg, "r");
if (infile == NULL)
fatal("%s (%s).", strerror(errno), optarg);
} else
fatal("Filename already specified.");
break;
case 'h':
default:
usage();
}
}
if (optind == argc || argc > (optind + 2))
usage();
userhost = xstrdup(argv[optind]);
file2 = argv[optind+1];
if ((cp = colon(userhost)) != NULL) {
*cp++ = '\0';
file1 = cp;
}
if ((host = strchr(userhost, '@')) == NULL)
host = userhost;
else {
*host++ = '\0';
if (!userhost[0]) {
fprintf(stderr, "Missing username\n");
usage();
}
make_ssh_args("-l");
make_ssh_args(userhost);
}
host = cleanhostname(host);
if (!*host) {
fprintf(stderr, "Missing hostname\n");
usage();
}
/* Set up logging and debug '-d' arguments to ssh */
ll = SYSLOG_LEVEL_INFO;
switch (debug_level) {
case 1:
ll = SYSLOG_LEVEL_DEBUG1;
make_ssh_args("-v");
break;
case 2:
ll = SYSLOG_LEVEL_DEBUG2;
make_ssh_args("-v");
make_ssh_args("-v");
break;
case 3:
ll = SYSLOG_LEVEL_DEBUG3;
make_ssh_args("-v");
make_ssh_args("-v");
make_ssh_args("-v");
break;
}
if (compress_flag)
make_ssh_args("-C");
log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
make_ssh_args(host);
fprintf(stderr, "Connecting to %s...\n", host);
connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid);
interactive_loop(in, out, file1, file2);
close(in);
close(out);
if (infile != stdin)
fclose(infile);
if (waitpid(sshpid, NULL, 0) == -1)
fatal("Couldn't wait for ssh process: %s", strerror(errno));
exit(0);
}

91
crypto/openssh/sftp.h Normal file
View File

@ -0,0 +1,91 @@
/* $OpenBSD: sftp.h,v 1.3 2001/03/07 10:11:23 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* draft-ietf-secsh-filexfer-01.txt
*/
/* version */
#define SSH2_FILEXFER_VERSION 3
/* client to server */
#define SSH2_FXP_INIT 1
#define SSH2_FXP_OPEN 3
#define SSH2_FXP_CLOSE 4
#define SSH2_FXP_READ 5
#define SSH2_FXP_WRITE 6
#define SSH2_FXP_LSTAT 7
#define SSH2_FXP_FSTAT 8
#define SSH2_FXP_SETSTAT 9
#define SSH2_FXP_FSETSTAT 10
#define SSH2_FXP_OPENDIR 11
#define SSH2_FXP_READDIR 12
#define SSH2_FXP_REMOVE 13
#define SSH2_FXP_MKDIR 14
#define SSH2_FXP_RMDIR 15
#define SSH2_FXP_REALPATH 16
#define SSH2_FXP_STAT 17
#define SSH2_FXP_RENAME 18
#define SSH2_FXP_READLINK 19
#define SSH2_FXP_SYMLINK 20
/* server to client */
#define SSH2_FXP_VERSION 2
#define SSH2_FXP_STATUS 101
#define SSH2_FXP_HANDLE 102
#define SSH2_FXP_DATA 103
#define SSH2_FXP_NAME 104
#define SSH2_FXP_ATTRS 105
#define SSH2_FXP_EXTENDED 200
#define SSH2_FXP_EXTENDED_REPLY 201
/* attributes */
#define SSH2_FILEXFER_ATTR_SIZE 0x00000001
#define SSH2_FILEXFER_ATTR_UIDGID 0x00000002
#define SSH2_FILEXFER_ATTR_PERMISSIONS 0x00000004
#define SSH2_FILEXFER_ATTR_ACMODTIME 0x00000008
#define SSH2_FILEXFER_ATTR_EXTENDED 0x80000000
/* portable open modes */
#define SSH2_FXF_READ 0x00000001
#define SSH2_FXF_WRITE 0x00000002
#define SSH2_FXF_APPEND 0x00000004
#define SSH2_FXF_CREAT 0x00000008
#define SSH2_FXF_TRUNC 0x00000010
#define SSH2_FXF_EXCL 0x00000020
/* status messages */
#define SSH2_FX_OK 0
#define SSH2_FX_EOF 1
#define SSH2_FX_NO_SUCH_FILE 2
#define SSH2_FX_PERMISSION_DENIED 3
#define SSH2_FX_FAILURE 4
#define SSH2_FX_BAD_MESSAGE 5
#define SSH2_FX_NO_CONNECTION 6
#define SSH2_FX_CONNECTION_LOST 7
#define SSH2_FX_OP_UNSUPPORTED 8
#define SSH2_FX_MAX 8

View File

@ -0,0 +1,19 @@
# $OpenBSD: Makefile,v 1.4 2001/04/16 02:31:52 mouring Exp $
.PATH: ${.CURDIR}/..
PROG= sftp
BINOWN= root
BINMODE?=555
BINDIR= /usr/bin
MAN= sftp.1
SRCS= sftp.c sftp-client.c sftp-int.c sftp-common.c sftp-glob.c scp-common.c
.include <bsd.prog.mk>
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}

View File

@ -1,3 +1,5 @@
.\" $OpenBSD: ssh-add.1,v 1.24 2001/04/10 09:13:21 itojun Exp $
.\"
.\" -*- nroff -*-
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -11,9 +13,9 @@
.\" called by a name other than "ssh" or "Secure Shell".
.\"
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -56,6 +58,8 @@ If any file requires a passphrase,
.Nm
asks for the passphrase from the user.
The Passphrase it is read from the user's tty.
.Nm
retries the last passphrase if multiple identity files are given.
.Pp
The authentication agent must be running and must be an ancestor of
the current process for
@ -76,7 +80,7 @@ Deletes all identities from the agent.
.Sh FILES
.Bl -tag -width Ds
.It Pa $HOME/.ssh/identity
Contains the RSA authentication identity of the user.
Contains the protocol version 1 RSA authentication identity of the user.
This file should not be readable by anyone but the user.
Note that
.Nm
@ -88,7 +92,9 @@ This is the default file added by
.Nm
when no other files have been specified.
.It Pa $HOME/.ssh/id_dsa
Contains the DSA authentication identity of the user.
Contains the protocol version 2 DSA authentication identity of the user.
.It Pa $HOME/.ssh/id_rsa
Contains the protocol version 2 RSA authentication identity of the user.
.El
.Sh ENVIRONMENT
.Bl -tag -width Ds
@ -116,35 +122,17 @@ may be necessary to redirect the input from
.Pa /dev/null
to make this work.)
.El
.Sh AUTHOR
Tatu Ylonen <ylo@cs.hut.fi>
.Pp
OpenSSH
is a derivative of the original (free) ssh 1.2.12 release, but with bugs
removed and newer features re-added.
Rapidly after the 1.2.12 release,
newer versions bore successively more restrictive licenses.
This version of OpenSSH
.Bl -bullet
.It
has all components of a restrictive nature (i.e., patents, see
.Xr ssl 8 )
directly removed from the source code; any licensed or patented components
are chosen from
external libraries.
.It
has been updated to support ssh protocol 1.5.
.It
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It
supports one-time password authentication with
.Xr skey 1 .
.El
.Sh AUTHORS
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by Tatu Ylonen.
Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
Theo de Raadt and Dug Song
removed many bugs, re-added newer features and
created OpenSSH.
Markus Friedl contributed the support for SSH
protocol versions 1.5 and 2.0.
.Sh SEE ALSO
.Xr ssh 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,
.Xr sshd 8 ,
.Xr ssl 8
.Xr sshd 8

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.20 2001/03/04 00:51:25 markus Exp $
.PATH: ${.CURDIR}/..
PROG= ssh-add
@ -8,9 +10,9 @@ BINMODE?=555
BINDIR= /usr/bin
MAN= ssh-add.1
SRCS= ssh-add.c log-client.c
SRCS= ssh-add.c
.include <bsd.prog.mk>
LDADD+= -lcrypto -lutil -lz
DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ}
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-agent.1,v 1.16 2000/09/07 20:27:54 deraadt Exp $
.\" $OpenBSD: ssh-agent.1,v 1.24 2001/04/10 09:13:21 itojun Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -10,9 +10,9 @@
.\" incompatible with the protocol description in the RFC file, it must be
.\" called by a name other than "ssh" or "Secure Shell".
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -42,12 +42,12 @@
.Nd authentication agent
.Sh SYNOPSIS
.Nm ssh-agent
.Op Fl c Li | Fl s
.Op Fl k
.Oo
.Ar command
.Op Ar args ...
.Oc
.Ar args ...
.Nm ssh-agent
.Op Fl c Li | Fl s
.Nm ssh-agent
.Fl k
.Sh DESCRIPTION
.Nm
is a program to hold private keys used for public key authentication
@ -121,7 +121,7 @@ or
syntax can be generated) which can be evalled in the calling shell.
Later
.Xr ssh 1
look at these variables and use them to establish a connection to the agent.
looks at these variables and uses them to establish a connection to the agent.
.Pp
A unix-domain socket is created
.Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> ,
@ -142,7 +142,7 @@ line terminates.
.Sh FILES
.Bl -tag -width Ds
.It Pa $HOME/.ssh/identity
Contains the RSA authentication identity of the user.
Contains the protocol version 1 RSA authentication identity of the user.
This file should not be readable by anyone but the user.
It is possible to
specify a passphrase when generating the key; that passphrase will be
@ -153,42 +153,26 @@ but is normally added to the agent using
.Xr ssh-add 1
at login time.
.It Pa $HOME/.ssh/id_dsa
Contains the DSA authentication identity of the user.
.Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> ,
Contains the protocol version 2 DSA authentication identity of the user.
.It Pa $HOME/.ssh/id_rsa
Contains the protocol version 2 RSA authentication identity of the user.
.It Pa /tmp/ssh-XXXXXXXX/agent.<pid>
Unix-domain sockets used to contain the connection to the
authentication agent.
These sockets should only be readable by the owner.
The sockets should get automatically removed when the agent exits.
.El
.Sh AUTHOR
Tatu Ylonen <ylo@cs.hut.fi>
.Pp
OpenSSH
is a derivative of the original (free) ssh 1.2.12 release, but with bugs
removed and newer features re-added.
Rapidly after the 1.2.12 release,
newer versions bore successively more restrictive licenses.
This version of OpenSSH
.Bl -bullet
.It
has all components of a restrictive nature (i.e., patents, see
.Xr ssl 8 )
directly removed from the source code; any licensed or patented components
are chosen from
external libraries.
.It
has been updated to support ssh protocol 1.5.
.It
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It
supports one-time password authentication with
.Xr skey 1 .
.El
.Sh AUTHORS
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by Tatu Ylonen.
Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
Theo de Raadt and Dug Song
removed many bugs, re-added newer features and
created OpenSSH.
Markus Friedl contributed the support for SSH
protocol versions 1.5 and 2.0.
.Sh SEE ALSO
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-keygen 1 ,
.Xr sshd 8 ,
.Xr ssl 8
.Xr sshd 8

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.17 2001/03/04 00:51:25 markus Exp $
.PATH: ${.CURDIR}/..
PROG= ssh-agent
@ -8,9 +10,9 @@ BINMODE?=555
BINDIR= /usr/bin
MAN= ssh-agent.1
SRCS= ssh-agent.c log-client.c
SRCS= ssh-agent.c
.include <bsd.prog.mk>
LDADD+= -lcrypto -lutil -lz
DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ}
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}

217
crypto/openssh/ssh-dss.c Normal file
View File

@ -0,0 +1,217 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-dss.c,v 1.6 2001/02/08 19:30:52 itojun Exp $");
#include <openssl/bn.h>
#include <openssl/evp.h>
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "compat.h"
#include "log.h"
#include "key.h"
#include "ssh-dss.h"
#define INTBLOB_LEN 20
#define SIGBLOB_LEN (2*INTBLOB_LEN)
int
ssh_dss_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
{
u_char *digest;
u_char *ret;
DSA_SIG *sig;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
u_int rlen;
u_int slen;
u_int len, dlen;
u_char sigblob[SIGBLOB_LEN];
Buffer b;
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
error("ssh_dss_sign: no DSA key");
return -1;
}
dlen = evp_md->md_size;
digest = xmalloc(dlen);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL);
sig = DSA_do_sign(digest, dlen, key->dsa);
if (sig == NULL) {
fatal("ssh_dss_sign: cannot sign");
}
memset(digest, 0, dlen);
xfree(digest);
rlen = BN_num_bytes(sig->r);
slen = BN_num_bytes(sig->s);
if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
error("bad sig size %d %d", rlen, slen);
DSA_SIG_free(sig);
return -1;
}
debug("sig size %d %d", rlen, slen);
memset(sigblob, 0, SIGBLOB_LEN);
BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
DSA_SIG_free(sig);
if (datafellows & SSH_BUG_SIGBLOB) {
debug("datafellows");
ret = xmalloc(SIGBLOB_LEN);
memcpy(ret, sigblob, SIGBLOB_LEN);
if (lenp != NULL)
*lenp = SIGBLOB_LEN;
if (sigp != NULL)
*sigp = ret;
} else {
/* ietf-drafts */
buffer_init(&b);
buffer_put_cstring(&b, "ssh-dss");
buffer_put_string(&b, sigblob, SIGBLOB_LEN);
len = buffer_len(&b);
ret = xmalloc(len);
memcpy(ret, buffer_ptr(&b), len);
buffer_free(&b);
if (lenp != NULL)
*lenp = len;
if (sigp != NULL)
*sigp = ret;
}
return 0;
}
int
ssh_dss_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen)
{
Buffer b;
u_char *digest;
DSA_SIG *sig;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
u_char *sigblob;
char *txt;
u_int len, dlen;
int rlen;
int ret;
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
error("ssh_dss_verify: no DSA key");
return -1;
}
if (!(datafellows & SSH_BUG_SIGBLOB) &&
signaturelen == SIGBLOB_LEN) {
datafellows |= ~SSH_BUG_SIGBLOB;
log("autodetect SSH_BUG_SIGBLOB");
} else if ((datafellows & SSH_BUG_SIGBLOB) &&
signaturelen != SIGBLOB_LEN) {
log("autoremove SSH_BUG_SIGBLOB");
datafellows &= ~SSH_BUG_SIGBLOB;
}
debug("len %d datafellows %d", signaturelen, datafellows);
/* fetch signature */
if (datafellows & SSH_BUG_SIGBLOB) {
sigblob = signature;
len = signaturelen;
} else {
/* ietf-drafts */
char *ktype;
buffer_init(&b);
buffer_append(&b, (char *) signature, signaturelen);
ktype = buffer_get_string(&b, NULL);
if (strcmp("ssh-dss", ktype) != 0) {
error("ssh_dss_verify: cannot handle type %s", ktype);
buffer_free(&b);
return -1;
}
sigblob = (u_char *)buffer_get_string(&b, &len);
rlen = buffer_len(&b);
if(rlen != 0) {
error("remaining bytes in signature %d", rlen);
buffer_free(&b);
return -1;
}
buffer_free(&b);
xfree(ktype);
}
if (len != SIGBLOB_LEN) {
fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
}
/* parse signature */
sig = DSA_SIG_new();
sig->r = BN_new();
sig->s = BN_new();
BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
if (!(datafellows & SSH_BUG_SIGBLOB)) {
memset(sigblob, 0, len);
xfree(sigblob);
}
/* sha1 the data */
dlen = evp_md->md_size;
digest = xmalloc(dlen);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL);
ret = DSA_do_verify(digest, dlen, sig, key->dsa);
memset(digest, 0, dlen);
xfree(digest);
DSA_SIG_free(sig);
switch (ret) {
case 1:
txt = "correct";
break;
case 0:
txt = "incorrect";
break;
case -1:
default:
txt = "error";
break;
}
debug("ssh_dss_verify: signature %s", txt);
return ret;
}

41
crypto/openssh/ssh-dss.h Normal file
View File

@ -0,0 +1,41 @@
/* $OpenBSD: ssh-dss.h,v 1.3 2001/01/29 01:58:18 niklas Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DSA_H
#define DSA_H
int
ssh_dss_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen);
int
ssh_dss_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen);
#endif

View File

@ -1,3 +1,5 @@
.\" $OpenBSD: ssh-keygen.1,v 1.40 2001/04/23 21:57:07 markus Exp $
.\"
.\" -*- nroff -*-
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -11,9 +13,9 @@
.\" called by a name other than "ssh" or "Secure Shell".
.\"
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -40,11 +42,12 @@
.Os
.Sh NAME
.Nm ssh-keygen
.Nd authentication key generation
.Nd authentication key generation, management and conversion
.Sh SYNOPSIS
.Nm ssh-keygen
.Op Fl dq
.Op Fl q
.Op Fl b Ar bits
.Op Fl t Ar type
.Op Fl N Ar new_passphrase
.Op Fl C Ar comment
.Op Fl f Ar output_keyfile
@ -54,10 +57,10 @@
.Op Fl N Ar new_passphrase
.Op Fl f Ar keyfile
.Nm ssh-keygen
.Fl x
.Fl i
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl X
.Fl e
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl y
@ -71,23 +74,25 @@
.Fl l
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl R
.Fl B
.Op Fl f Ar input_keyfile
.Sh DESCRIPTION
.Nm
generates and manages authentication keys for
generates, manages and converts authentication keys for
.Xr ssh 1 .
.Nm
defaults to generating an RSA key for use by protocols 1.3 and 1.5;
defaults to generating a RSA1 key for use by SSH protocol version 1.
specifying the
.Fl d
flag will create a DSA key instead for use by protocol 2.0.
.Fl t
option allows you to create a key for use by SSH protocol version 2.
.Pp
Normally each user wishing to use SSH
with RSA or DSA authentication runs this once to create the authentication
key in
.Pa $HOME/.ssh/identity
.Pa $HOME/.ssh/identity ,
.Pa $HOME/.ssh/id_dsa
or
.Pa $HOME/.ssh/id_dsa .
.Pa $HOME/.ssh/id_rsa .
Additionally, the system administrator may use this to generate host keys,
as seen in
.Pa /etc/rc .
@ -99,7 +104,7 @@ The public key is stored in a file with the same name but
appended.
The program also asks for a passphrase.
The passphrase may be empty to indicate no passphrase
(host keys must have empty passphrase), or it may be a string of
(host keys must have an empty passphrase), or it may be a string of
arbitrary length.
Good passphrases are 10-30 characters long and are
not simple sentences or otherwise easily guessable (English
@ -114,7 +119,8 @@ If the passphrase is
lost or forgotten, you will have to generate a new key and copy the
corresponding public key to other machines.
.Pp
For RSA, there is also a comment field in the key file that is only for
For RSA1 keys,
there is also a comment field in the key file that is only for
convenience to the user to help identify the key.
The comment can tell what the key is for, or whatever is useful.
The comment is initialized to
@ -138,8 +144,24 @@ The default is 1024 bits.
Requests changing the comment in the private and public key files.
The program will prompt for the file containing the private keys, for
passphrase if the key has one, and for the new comment.
.It Fl e
This option will read a private or public OpenSSH key file and
print the key in a
.Sq SECSH Public Key File Format
to stdout.
This option allows exporting keys for use by several commercial
SSH implementations.
.It Fl f
Specifies the filename of the key file.
.It Fl i
This option will read an unencrypted private (or public) key file
in SSH2-compatible format and print an OpenSSH compatible private
(or public) key to stdout.
.Nm
also reads the
.Sq SECSH Public Key File Format .
This option allows importing keys from several commercial
SSH implementations.
.It Fl l
Show fingerprint of specified private or public key file.
.It Fl p
@ -154,31 +176,33 @@ Silence
Used by
.Pa /etc/rc
when creating a new key.
.It Fl y
This option will read a private
OpenSSH format file and print an OpenSSH public key to stdout.
.It Fl t Ar type
Specifies the type of the key to create.
The possible values are
.Dq rsa1
for protocol version 1 and
.Dq rsa
or
.Dq dsa
for protocol version 2.
The default is
.Dq rsa1 .
.It Fl B
Show the bubblebabble digest of specified private or public key file.
.It Fl C Ar comment
Provides the new comment.
.It Fl N Ar new_passphrase
Provides the new passphrase.
.It Fl P Ar passphrase
Provides the (old) passphrase.
.It Fl R
If RSA support is functional, immediately exits with code 0. If RSA
support is not functional, exits with code 1. This flag will be
removed once the RSA patent expires.
.It Fl x
This option will read a private
OpenSSH DSA format file and print a SSH2-compatible public key to stdout.
.It Fl X
This option will read a unencrypted
SSH2-compatible private (or public) key file and
print an OpenSSH compatible private (or public) key to stdout.
.It Fl y
This option will read a private
OpenSSH DSA format file and print an OpenSSH DSA public key to stdout.
.El
.Sh FILES
.Bl -tag -width Ds
.It Pa $HOME/.ssh/identity
Contains the RSA authentication identity of the user.
Contains the protocol version 1 RSA authentication identity of the user.
This file should not be readable by anyone but the user.
It is possible to
specify a passphrase when generating the key; that passphrase will be
@ -189,14 +213,14 @@ but it is offered as the default file for the private key.
.Xr sshd 8
will read this file when a login attempt is made.
.It Pa $HOME/.ssh/identity.pub
Contains the public key for authentication.
Contains the protocol version 1 RSA public key for authentication.
The contents of this file should be added to
.Pa $HOME/.ssh/authorized_keys
on all machines
where you wish to log in using RSA authentication.
There is no need to keep the contents of this file secret.
.It Pa $HOME/.ssh/id_dsa
Contains the DSA authentication identity of the user.
Contains the protocol version 2 DSA authentication identity of the user.
This file should not be readable by anyone but the user.
It is possible to
specify a passphrase when generating the key; that passphrase will be
@ -207,42 +231,50 @@ but it is offered as the default file for the private key.
.Xr sshd 8
will read this file when a login attempt is made.
.It Pa $HOME/.ssh/id_dsa.pub
Contains the public key for authentication.
Contains the protocol version 2 DSA public key for authentication.
The contents of this file should be added to
.Pa $HOME/.ssh/authorized_keys2
on all machines
where you wish to log in using DSA authentication.
where you wish to log in using public key authentication.
There is no need to keep the contents of this file secret.
.It Pa $HOME/.ssh/id_rsa
Contains the protocol version 2 RSA authentication identity of the user.
This file should not be readable by anyone but the user.
It is possible to
specify a passphrase when generating the key; that passphrase will be
used to encrypt the private part of this file using 3DES.
This file is not automatically accessed by
.Nm
but it is offered as the default file for the private key.
.Xr sshd 8
will read this file when a login attempt is made.
.It Pa $HOME/.ssh/id_rsa.pub
Contains the protocol version 2 RSA public key for authentication.
The contents of this file should be added to
.Pa $HOME/.ssh/authorized_keys2
on all machines
where you wish to log in using public key authentication.
There is no need to keep the contents of this file secret.
.El
.Sh AUTHOR
Tatu Ylonen <ylo@cs.hut.fi>
.Pp
OpenSSH
is a derivative of the original (free) ssh 1.2.12 release, but with bugs
removed and newer features re-added.
Rapidly after the 1.2.12 release,
newer versions bore successively more restrictive licenses.
This version of OpenSSH
.Bl -bullet
.It
has all components of a restrictive nature (i.e., patents, see
.Xr ssl 8 )
directly removed from the source code; any licensed or patented components
are chosen from
external libraries.
.It
has been updated to support ssh protocol 1.5.
.It
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It
supports one-time password authentication with
.Xr skey 1 .
.El
.Sh AUTHORS
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by Tatu Ylonen.
Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
Theo de Raadt and Dug Song
removed many bugs, re-added newer features and
created OpenSSH.
Markus Friedl contributed the support for SSH
protocol versions 1.5 and 2.0.
.Sh SEE ALSO
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr sshd 8 ,
.Xr ssl 8
.Xr sshd 8
.Rs
.%A J. Galbraith
.%A R. Thayer
.%T "SECSH Public Key File Format"
.%N draft-ietf-secsh-publickeyfile-01.txt
.%D March 2001
.%O work in progress material
.Re

View File

@ -12,23 +12,21 @@
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $");
RCSID("$OpenBSD: ssh-keygen.c,v 1.60 2001/04/23 22:14:13 markus Exp $");
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "ssh.h"
#include "xmalloc.h"
#include "key.h"
#include "rsa.h"
#include "dsa.h"
#include "authfile.h"
#include "uuencode.h"
#include "buffer.h"
#include "bufaux.h"
#include "pathnames.h"
#include "log.h"
#include "readpass.h"
/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
int bits = 1024;
@ -49,6 +47,7 @@ int quiet = 0;
/* Flag indicating that we just want to see the key fingerprint */
int print_fingerprint = 0;
int print_bubblebabble = 0;
/* The identity file name, given on the command line or entered by the user. */
char identity_file[1024];
@ -67,7 +66,9 @@ char *identity_comment = NULL;
int convert_to_ssh2 = 0;
int convert_from_ssh2 = 0;
int print_public = 0;
int dsa_mode = 0;
/* default to RSA for SSH-1 */
char *key_type_name = "rsa1";
/* argv0 */
extern char *__progname;
@ -78,11 +79,26 @@ void
ask_filename(struct passwd *pw, const char *prompt)
{
char buf[1024];
snprintf(identity_file, sizeof(identity_file), "%s/%s",
pw->pw_dir,
dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY);
printf("%s (%s): ", prompt, identity_file);
fflush(stdout);
char *name = NULL;
switch (key_type_from_name(key_type_name)) {
case KEY_RSA1:
name = _PATH_SSH_CLIENT_IDENTITY;
break;
case KEY_DSA:
name = _PATH_SSH_CLIENT_ID_DSA;
break;
case KEY_RSA:
name = _PATH_SSH_CLIENT_ID_RSA;
break;
default:
fprintf(stderr, "bad key type");
exit(1);
break;
}
snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
fprintf(stderr, "%s (%s): ", prompt, identity_file);
fflush(stderr);
if (fgets(buf, sizeof(buf), stdin) == NULL)
exit(1);
if (strchr(buf, '\n'))
@ -92,32 +108,33 @@ ask_filename(struct passwd *pw, const char *prompt)
have_identity = 1;
}
int
try_load_key(char *filename, Key *k)
Key *
try_load_pem_key(char *filename)
{
int success = 1;
if (!load_private_key(filename, "", k, NULL)) {
char *pass = read_passphrase("Enter passphrase: ", 1);
if (!load_private_key(filename, pass, k, NULL)) {
success = 0;
}
char *pass;
Key *prv;
prv = key_load_private(filename, "", NULL);
if (prv == NULL) {
pass = read_passphrase("Enter passphrase: ", 1);
prv = key_load_private(filename, pass, NULL);
memset(pass, 0, strlen(pass));
xfree(pass);
}
return success;
return prv;
}
#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
void
do_convert_to_ssh2(struct passwd *pw)
{
Key *k;
int len;
unsigned char *blob;
u_char *blob;
struct stat st;
if (!have_identity)
@ -126,12 +143,13 @@ do_convert_to_ssh2(struct passwd *pw)
perror(identity_file);
exit(1);
}
k = key_new(KEY_DSA);
if (!try_load_key(identity_file, k)) {
fprintf(stderr, "load failed\n");
exit(1);
if ((k = key_load_public(identity_file, NULL)) == NULL) {
if ((k = try_load_pem_key(identity_file)) == NULL) {
fprintf(stderr, "load failed\n");
exit(1);
}
}
dsa_make_key_blob(k, &blob, &len);
key_to_blob(k, &blob, &len);
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
fprintf(stdout,
"Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
@ -149,9 +167,11 @@ buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
{
int bits = buffer_get_int(b);
int bytes = (bits + 7) / 8;
if (buffer_len(b) < bytes)
fatal("buffer_get_bignum_bits: input buffer too small");
BN_bin2bn((unsigned char *)buffer_ptr(b), bytes, value);
fatal("buffer_get_bignum_bits: input buffer too small: "
"need %d have %d", bytes, buffer_len(b));
BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
buffer_consume(b, bytes);
}
@ -159,9 +179,8 @@ Key *
do_convert_private_ssh2_from_blob(char *blob, int blen)
{
Buffer b;
DSA *dsa;
Key *key = NULL;
int ignore, magic, rlen;
int ignore, magic, rlen, ktype;
char *type, *cipher;
buffer_init(&b);
@ -179,33 +198,64 @@ do_convert_private_ssh2_from_blob(char *blob, int blen)
ignore = buffer_get_int(&b);
ignore = buffer_get_int(&b);
ignore = buffer_get_int(&b);
xfree(type);
if (strcmp(cipher, "none") != 0) {
error("unsupported cipher %s", cipher);
xfree(cipher);
buffer_free(&b);
xfree(type);
return NULL;
}
xfree(cipher);
key = key_new(KEY_DSA);
dsa = key->dsa;
dsa->priv_key = BN_new();
if (dsa->priv_key == NULL) {
error("alloc priv_key failed");
key_free(key);
if (strstr(type, "dsa")) {
ktype = KEY_DSA;
} else if (strstr(type, "rsa")) {
ktype = KEY_RSA;
} else {
xfree(type);
return NULL;
}
buffer_get_bignum_bits(&b, dsa->p);
buffer_get_bignum_bits(&b, dsa->g);
buffer_get_bignum_bits(&b, dsa->q);
buffer_get_bignum_bits(&b, dsa->pub_key);
buffer_get_bignum_bits(&b, dsa->priv_key);
key = key_new_private(ktype);
xfree(type);
switch (key->type) {
case KEY_DSA:
buffer_get_bignum_bits(&b, key->dsa->p);
buffer_get_bignum_bits(&b, key->dsa->g);
buffer_get_bignum_bits(&b, key->dsa->q);
buffer_get_bignum_bits(&b, key->dsa->pub_key);
buffer_get_bignum_bits(&b, key->dsa->priv_key);
break;
case KEY_RSA:
if (!BN_set_word(key->rsa->e, (u_long) buffer_get_char(&b))) {
buffer_free(&b);
key_free(key);
return NULL;
}
buffer_get_bignum_bits(&b, key->rsa->d);
buffer_get_bignum_bits(&b, key->rsa->n);
buffer_get_bignum_bits(&b, key->rsa->iqmp);
buffer_get_bignum_bits(&b, key->rsa->q);
buffer_get_bignum_bits(&b, key->rsa->p);
generate_additional_parameters(key->rsa);
break;
}
rlen = buffer_len(&b);
if(rlen != 0)
error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen);
error("do_convert_private_ssh2_from_blob: "
"remaining bytes in key blob %d", rlen);
buffer_free(&b);
#ifdef DEBUG_PK
{
u_int slen;
u_char *sig, data[10] = "abcde12345";
key_sign(key, &sig, &slen, data, sizeof data);
key_verify(key, sig, slen, data, sizeof data);
xfree(sig);
}
#endif
return key;
}
@ -244,31 +294,33 @@ do_convert_from_ssh2(struct passwd *pw)
strstr(line, ": ") != NULL) {
if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
private = 1;
fprintf(stderr, "ignore: %s", line);
/* fprintf(stderr, "ignore: %s", line); */
continue;
}
if (escaped) {
escaped--;
fprintf(stderr, "escaped: %s", line);
/* fprintf(stderr, "escaped: %s", line); */
continue;
}
*p = '\0';
strlcat(encoded, line, sizeof(encoded));
}
blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
if (blen < 0) {
fprintf(stderr, "uudecode failed.\n");
exit(1);
}
k = private ?
do_convert_private_ssh2_from_blob(blob, blen) :
dsa_key_from_blob(blob, blen);
key_from_blob(blob, blen);
if (k == NULL) {
fprintf(stderr, "decode blob failed.\n");
exit(1);
}
ok = private ?
PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
(k->type == KEY_DSA ?
PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
key_write(k, stdout);
if (!ok) {
fprintf(stderr, "key write failed");
@ -283,9 +335,7 @@ do_convert_from_ssh2(struct passwd *pw)
void
do_print_public(struct passwd *pw)
{
Key *k;
int len;
unsigned char *blob;
Key *prv;
struct stat st;
if (!have_identity)
@ -294,16 +344,14 @@ do_print_public(struct passwd *pw)
perror(identity_file);
exit(1);
}
k = key_new(KEY_DSA);
if (!try_load_key(identity_file, k)) {
prv = try_load_pem_key(identity_file);
if (prv == NULL) {
fprintf(stderr, "load failed\n");
exit(1);
}
dsa_make_key_blob(k, &blob, &len);
if (!key_write(k, stdout))
if (!key_write(prv, stdout))
fprintf(stderr, "key_write failed");
key_free(k);
xfree(blob);
key_free(prv);
fprintf(stdout, "\n");
exit(0);
}
@ -311,28 +359,32 @@ do_print_public(struct passwd *pw)
void
do_fingerprint(struct passwd *pw)
{
/* XXX RSA1 only */
FILE *f;
Key *public;
char *comment = NULL, *cp, *ep, line[16*1024];
int i, skip = 0, num = 1, invalid = 1;
unsigned int ignore;
char *comment = NULL, *cp, *ep, line[16*1024], *fp;
int i, skip = 0, num = 1, invalid = 1, rep, fptype;
struct stat st;
fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) < 0) {
perror(identity_file);
exit(1);
}
public = key_new(KEY_RSA);
if (load_public_key(identity_file, public, &comment)) {
printf("%d %s %s\n", BN_num_bits(public->rsa->n),
key_fingerprint(public), comment);
public = key_load_public(identity_file, &comment);
if (public != NULL) {
fp = key_fingerprint(public, fptype, rep);
printf("%d %s %s\n", key_size(public), fp, comment);
key_free(public);
xfree(comment);
xfree(fp);
exit(0);
}
if (comment)
xfree(comment);
f = fopen(identity_file, "r");
if (f != NULL) {
@ -370,17 +422,26 @@ do_fingerprint(struct passwd *pw)
*cp++ = '\0';
}
ep = cp;
if (auth_rsa_read_key(&cp, &ignore, public->rsa->e, public->rsa->n)) {
invalid = 0;
comment = *cp ? cp : comment;
printf("%d %s %s\n", key_size(public),
key_fingerprint(public),
comment ? comment : "no comment");
public = key_new(KEY_RSA1);
if (key_read(public, &cp) != 1) {
cp = ep;
key_free(public);
public = key_new(KEY_UNSPEC);
if (key_read(public, &cp) != 1) {
key_free(public);
continue;
}
}
comment = *cp ? cp : comment;
fp = key_fingerprint(public, fptype, rep);
printf("%d %s %s\n", key_size(public), fp,
comment ? comment : "no comment");
xfree(fp);
key_free(public);
invalid = 0;
}
fclose(f);
}
key_free(public);
if (invalid) {
printf("%s is not a valid key file.\n", identity_file);
exit(1);
@ -399,8 +460,6 @@ do_change_passphrase(struct passwd *pw)
char *old_passphrase, *passphrase1, *passphrase2;
struct stat st;
Key *private;
Key *public;
int type = dsa_mode ? KEY_DSA : KEY_RSA;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
@ -408,33 +467,20 @@ do_change_passphrase(struct passwd *pw)
perror(identity_file);
exit(1);
}
if (type == KEY_RSA) {
/* XXX this works currently only for RSA */
public = key_new(type);
if (!load_public_key(identity_file, public, NULL)) {
printf("%s is not a valid key file.\n", identity_file);
exit(1);
}
/* Clear the public key since we are just about to load the whole file. */
key_free(public);
}
/* Try to load the file with empty passphrase. */
private = key_new(type);
if (!load_private_key(identity_file, "", private, &comment)) {
private = key_load_private(identity_file, "", &comment);
if (private == NULL) {
if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase);
else
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase);
private = key_load_private(identity_file, old_passphrase , &comment);
memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase);
if (private == NULL) {
printf("Bad passphrase.\n");
exit(1);
}
memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase);
}
printf("Key has comment '%s'\n", comment);
@ -462,9 +508,8 @@ do_change_passphrase(struct passwd *pw)
}
/* Save the file using the new passphrase. */
if (!save_private_key(identity_file, passphrase1, private, comment)) {
printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno));
if (!key_save_private(private, identity_file, passphrase1, comment)) {
printf("Saving the key failed: %s.\n", identity_file);
memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1);
key_free(private);
@ -487,12 +532,12 @@ do_change_passphrase(struct passwd *pw)
void
do_change_comment(struct passwd *pw)
{
char new_comment[1024], *comment;
char new_comment[1024], *comment, *passphrase;
Key *private;
Key *public;
char *passphrase;
struct stat st;
FILE *f;
int fd;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
@ -500,20 +545,8 @@ do_change_comment(struct passwd *pw)
perror(identity_file);
exit(1);
}
/*
* Try to load the public key from the file the verify that it is
* readable and of the proper format.
*/
public = key_new(KEY_RSA);
if (!load_public_key(identity_file, public, NULL)) {
printf("%s is not a valid key file.\n", identity_file);
exit(1);
}
private = key_new(KEY_RSA);
if (load_private_key(identity_file, "", private, &comment))
passphrase = xstrdup("");
else {
private = key_load_private(identity_file, "", &comment);
if (private == NULL) {
if (identity_passphrase)
passphrase = xstrdup(identity_passphrase);
else if (identity_new_passphrase)
@ -521,13 +554,21 @@ do_change_comment(struct passwd *pw)
else
passphrase = read_passphrase("Enter passphrase: ", 1);
/* Try to load using the passphrase. */
if (!load_private_key(identity_file, passphrase, private, &comment)) {
private = key_load_private(identity_file, passphrase, &comment);
if (private == NULL) {
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
printf("Bad passphrase.\n");
exit(1);
}
} else {
passphrase = xstrdup("");
}
if (private->type != KEY_RSA1) {
fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
key_free(private);
exit(1);
}
printf("Key now has comment '%s'\n", comment);
if (identity_comment) {
@ -545,9 +586,8 @@ do_change_comment(struct passwd *pw)
}
/* Save the file using the new passphrase. */
if (!save_private_key(identity_file, passphrase, private, new_comment)) {
printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno));
if (!key_save_private(private, identity_file, passphrase, new_comment)) {
printf("Saving the key failed: %s.\n", identity_file);
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
key_free(private);
@ -556,14 +596,20 @@ do_change_comment(struct passwd *pw)
}
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
public = key_from_private(private);
key_free(private);
strlcat(identity_file, ".pub", sizeof(identity_file));
f = fopen(identity_file, "w");
if (!f) {
fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
printf("Could not save your public key in %s\n", identity_file);
exit(1);
}
f = fdopen(fd, "w");
if (f == NULL) {
printf("fdopen %s failed", identity_file);
exit(1);
}
if (!key_write(public, f))
fprintf(stderr, "write key failed");
key_free(public);
@ -579,7 +625,8 @@ do_change_comment(struct passwd *pw)
void
usage(void)
{
printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname);
printf("Usage: %s [-ceilpqyB] [-t type] [-b bits] [-f file] [-C comment] "
"[-N new-pass] [-P pass]\n", __progname);
exit(1);
}
@ -590,12 +637,12 @@ int
main(int ac, char **av)
{
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
Key *private, *public;
struct passwd *pw;
int opt;
int opt, type, fd;
struct stat st;
FILE *f;
Key *private;
Key *public;
extern int optind;
extern char *optarg;
@ -612,7 +659,7 @@ main(int ac, char **av)
exit(1);
}
while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:P:N:C:")) != -1) {
switch (opt) {
case 'b':
bits = atoi(optarg);
@ -626,6 +673,10 @@ main(int ac, char **av)
print_fingerprint = 1;
break;
case 'B':
print_bubblebabble = 1;
break;
case 'p':
change_passphrase = 1;
break;
@ -656,17 +707,19 @@ main(int ac, char **av)
break;
case 'R':
if (rsa_alive() == 0)
exit(1);
else
exit(0);
/* unused */
exit(0);
break;
case 'e':
case 'x':
/* export key */
convert_to_ssh2 = 1;
break;
case 'i':
case 'X':
/* import key */
convert_from_ssh2 = 1;
break;
@ -675,7 +728,11 @@ main(int ac, char **av)
break;
case 'd':
dsa_mode = 1;
key_type_name = "dsa";
break;
case 't':
key_type_name = optarg;
break;
case '?':
@ -691,14 +748,7 @@ main(int ac, char **av)
printf("Can only have one of -p and -c.\n");
usage();
}
/* check if RSA support is needed and exists */
if (dsa_mode == 0 && rsa_alive() == 0) {
fprintf(stderr,
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
__progname);
exit(1);
}
if (print_fingerprint)
if (print_fingerprint || print_bubblebabble)
do_fingerprint(pw);
if (change_passphrase)
do_change_passphrase(pw);
@ -713,28 +763,25 @@ main(int ac, char **av)
arc4random_stir();
if (dsa_mode != 0) {
if (!quiet)
printf("Generating DSA parameter and key.\n");
public = private = dsa_generate_key(bits);
if (private == NULL) {
fprintf(stderr, "dsa_generate_keys failed");
exit(1);
}
} else {
if (quiet)
rsa_set_verbose(0);
/* Generate the rsa key pair. */
public = key_new(KEY_RSA);
private = key_new(KEY_RSA);
rsa_generate_key(private->rsa, public->rsa, bits);
type = key_type_from_name(key_type_name);
if (type == KEY_UNSPEC) {
fprintf(stderr, "unknown key type %s\n", key_type_name);
exit(1);
}
if (!quiet)
printf("Generating public/private %s key pair.\n", key_type_name);
private = key_generate(type, bits);
if (private == NULL) {
fprintf(stderr, "key_generate failed");
exit(1);
}
public = key_from_private(private);
if (!have_identity)
ask_filename(pw, "Enter file in which to save the key");
/* Create ~/.ssh directory if it doesn\'t already exist. */
snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
if (strstr(identity_file, dotsshdir) != NULL &&
stat(dotsshdir, &st) < 0) {
if (mkdir(dotsshdir, 0700) < 0)
@ -785,9 +832,8 @@ main(int ac, char **av)
}
/* Save the key with the given passphrase and comment. */
if (!save_private_key(identity_file, passphrase1, private, comment)) {
printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno));
if (!key_save_private(private, identity_file, passphrase1, comment)) {
printf("Saving the key failed: %s.\n", identity_file);
memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1);
exit(1);
@ -797,30 +843,35 @@ main(int ac, char **av)
xfree(passphrase1);
/* Clear the private key and the random number generator. */
if (private != public) {
key_free(private);
}
key_free(private);
arc4random_stir();
if (!quiet)
printf("Your identification has been saved in %s.\n", identity_file);
strlcat(identity_file, ".pub", sizeof(identity_file));
f = fopen(identity_file, "w");
if (!f) {
fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
printf("Could not save your public key in %s\n", identity_file);
exit(1);
}
f = fdopen(fd, "w");
if (f == NULL) {
printf("fdopen %s failed", identity_file);
exit(1);
}
if (!key_write(public, f))
fprintf(stderr, "write key failed");
fprintf(f, " %s\n", comment);
fclose(f);
if (!quiet) {
char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
printf("Your public key has been saved in %s.\n",
identity_file);
printf("The key fingerprint is:\n");
printf("%s %s\n", key_fingerprint(public), comment);
printf("%s %s\n", fp, comment);
xfree(fp);
}
key_free(public);

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.17 2001/03/04 00:51:26 markus Exp $
.PATH: ${.CURDIR}/..
PROG= ssh-keygen
@ -8,9 +10,9 @@ BINMODE?=555
BINDIR= /usr/bin
MAN= ssh-keygen.1
SRCS= ssh-keygen.c log-client.c
SRCS= ssh-keygen.c
.include <bsd.prog.mk>
LDADD+= -lcrypto -lutil -lz
DPADD+= ${LIBCRYPTO} ${LIBDES} ${LIBUTIL} ${LIBZ}
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}

View File

@ -0,0 +1,104 @@
.\" $OpenBSD: ssh-keyscan.1,v 1.5 2001/04/18 16:21:05 ian Exp $
.\"
.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
.\"
.\" Modification and redistribution in source and binary forms is
.\" permitted provided that due credit is given to the author and the
.\" OpenBSD project (for instance by leaving this copyright notice
.\" intact).
.\"
.Dd January 1, 1996
.Dt SSH-KEYSCAN 1
.Os
.Sh NAME
.Nm ssh-keyscan
.Nd gather ssh public keys
.Sh SYNOPSIS
.Nm ssh-keyscan
.Op Fl t Ar timeout
.Op Ar -- | host | addrlist namelist
.Op Fl f Ar files ...
.Sh DESCRIPTION
.Nm
is a utility for gathering the public ssh host keys of a number of
hosts. It was designed to aid in building and verifying
.Pa ssh_known_hosts
files.
.Nm
provides a minimal interface suitable for use by shell and perl
scripts.
.Pp
.Nm
uses non-blocking socket I/O to contact as many hosts as possible in
parallel, so it is very efficient. The keys from a domain of 1,000
hosts can be collected in tens of seconds, even when some of those
hosts are down or do not run ssh. You do not need login access to the
machines you are scanning, nor does the scanning process involve
any encryption.
.Sh SECURITY
If you make an ssh_known_hosts file using
.Nm
without verifying the keys, you will be vulnerable to
.I man in the middle
attacks.
On the other hand, if your security model allows such a risk,
.Nm
can help you detect tampered keyfiles or man in the middle attacks which
have begun after you created your ssh_known_hosts file.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl t
Set the timeout for connection attempts. If
.Pa timeout
seconds have elapsed since a connection was initiated to a host or since the
last time anything was read from that host, then the connection is
closed and the host in question considered unavailable. Default is 5
seconds.
.It Fl f
Read hosts or
.Pa addrlist namelist
pairs from this file, one per line.
If
.Pa -
is supplied instead of a filename,
.Nm
will read hosts or
.Pa addrlist namelist
pairs from the standard input.
.El
.Sh EXAMPLES
.Pp
Print the host key for machine
.Pa hostname :
.Bd -literal
ssh-keyscan hostname
.Ed
.Pp
Find all hosts from the file
.Pa ssh_hosts
which have new or different keys from those in the sorted file
.Pa ssh_known_hosts :
.Bd -literal
$ ssh-keyscan -f ssh_hosts | sort -u - ssh_known_hosts | \e\
diff ssh_known_hosts -
.Ed
.Pp
.Sh FILES
.Pp
.Pa Input format:
1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
.Pp
.Pa Output format:
host-or-namelist bits exponent modulus
.Pp
.Pa /etc/ssh_known_hosts
.Sh BUGS
It generates "Connection closed by remote host" messages on the consoles
of all the machines it scans.
This is because it opens a connection to the ssh port, reads the public
key, and drops the connection as soon as it gets the key.
.Sh SEE ALSO
.Xr ssh 1 ,
.Xr sshd 8
.Sh AUTHOR
David Mazieres <dm@lcs.mit.edu>

View File

@ -0,0 +1,625 @@
/*
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
*
* Modification and redistribution in source and binary forms is
* permitted provided that due credit is given to the author and the
* OpenBSD project (for instance by leaving this copyright notice
* intact).
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-keyscan.c,v 1.22 2001/03/06 06:11:18 deraadt Exp $");
#include <sys/queue.h>
#include <errno.h>
#include <openssl/bn.h>
#include "xmalloc.h"
#include "ssh.h"
#include "ssh1.h"
#include "key.h"
#include "buffer.h"
#include "bufaux.h"
#include "log.h"
#include "atomicio.h"
static int argno = 1; /* Number of argument currently being parsed */
int family = AF_UNSPEC; /* IPv4, IPv6 or both */
#define MAXMAXFD 256
/* The number of seconds after which to give up on a TCP connection */
int timeout = 5;
int maxfd;
#define MAXCON (maxfd - 10)
extern char *__progname;
fd_set *read_wait;
size_t read_wait_size;
int ncon;
/*
* Keep a connection structure for each file descriptor. The state
* associated with file descriptor n is held in fdcon[n].
*/
typedef struct Connection {
u_char c_status; /* State of connection on this file desc. */
#define CS_UNUSED 0 /* File descriptor unused */
#define CS_CON 1 /* Waiting to connect/read greeting */
#define CS_SIZE 2 /* Waiting to read initial packet size */
#define CS_KEYS 3 /* Waiting to read public key packet */
int c_fd; /* Quick lookup: c->c_fd == c - fdcon */
int c_plen; /* Packet length field for ssh packet */
int c_len; /* Total bytes which must be read. */
int c_off; /* Length of data read so far. */
char *c_namebase; /* Address to free for c_name and c_namelist */
char *c_name; /* Hostname of connection for errors */
char *c_namelist; /* Pointer to other possible addresses */
char *c_output_name; /* Hostname of connection for output */
char *c_data; /* Data read from this fd */
struct timeval c_tv; /* Time at which connection gets aborted */
TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
} con;
TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */
con *fdcon;
/*
* This is just a wrapper around fgets() to make it usable.
*/
/* Stress-test. Increase this later. */
#define LINEBUF_SIZE 16
typedef struct {
char *buf;
u_int size;
int lineno;
const char *filename;
FILE *stream;
void (*errfun) (const char *,...);
} Linebuf;
Linebuf *
Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
{
Linebuf *lb;
if (!(lb = malloc(sizeof(*lb)))) {
if (errfun)
(*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
return (NULL);
}
if (filename) {
lb->filename = filename;
if (!(lb->stream = fopen(filename, "r"))) {
xfree(lb);
if (errfun)
(*errfun) ("%s: %s\n", filename, strerror(errno));
return (NULL);
}
} else {
lb->filename = "(stdin)";
lb->stream = stdin;
}
if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) {
if (errfun)
(*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
xfree(lb);
return (NULL);
}
lb->errfun = errfun;
lb->lineno = 0;
return (lb);
}
void
Linebuf_free(Linebuf * lb)
{
fclose(lb->stream);
xfree(lb->buf);
xfree(lb);
}
void
Linebuf_restart(Linebuf * lb)
{
clearerr(lb->stream);
rewind(lb->stream);
lb->lineno = 0;
}
int
Linebuf_lineno(Linebuf * lb)
{
return (lb->lineno);
}
char *
Linebuf_getline(Linebuf * lb)
{
int n = 0;
lb->lineno++;
for (;;) {
/* Read a line */
if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) {
if (ferror(lb->stream) && lb->errfun)
(*lb->errfun) ("%s: %s\n", lb->filename,
strerror(errno));
return (NULL);
}
n = strlen(lb->buf);
/* Return it or an error if it fits */
if (n > 0 && lb->buf[n - 1] == '\n') {
lb->buf[n - 1] = '\0';
return (lb->buf);
}
if (n != lb->size - 1) {
if (lb->errfun)
(*lb->errfun) ("%s: skipping incomplete last line\n",
lb->filename);
return (NULL);
}
/* Double the buffer if we need more space */
if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) {
if (lb->errfun)
(*lb->errfun) ("linebuf (%s): realloc failed\n",
lb->filename);
return (NULL);
}
}
}
int
fdlim_get(int hard)
{
struct rlimit rlfd;
if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
return (-1);
if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
return 10000;
else
return hard ? rlfd.rlim_max : rlfd.rlim_cur;
}
int
fdlim_set(int lim)
{
struct rlimit rlfd;
if (lim <= 0)
return (-1);
if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
return (-1);
rlfd.rlim_cur = lim;
if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0)
return (-1);
return (0);
}
/*
* This is an strsep function that returns a null field for adjacent
* separators. This is the same as the 4.4BSD strsep, but different from the
* one in the GNU libc.
*/
char *
xstrsep(char **str, const char *delim)
{
char *s, *e;
if (!**str)
return (NULL);
s = *str;
e = s + strcspn(s, delim);
if (*e != '\0')
*e++ = '\0';
*str = e;
return (s);
}
/*
* Get the next non-null token (like GNU strsep). Strsep() will return a
* null token for two adjacent separators, so we may have to loop.
*/
char *
strnnsep(char **stringp, char *delim)
{
char *tok;
do {
tok = xstrsep(stringp, delim);
} while (tok && *tok == '\0');
return (tok);
}
void
keyprint(char *host, char *output_name, char *kd, int len)
{
static Key *rsa;
static Buffer msg;
if (rsa == NULL) {
buffer_init(&msg);
rsa = key_new(KEY_RSA1);
}
buffer_append(&msg, kd, len);
buffer_consume(&msg, 8 - (len & 7)); /* padding */
if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
error("%s: invalid packet type", host);
buffer_clear(&msg);
return;
}
buffer_consume(&msg, 8); /* cookie */
/* server key */
(void) buffer_get_int(&msg);
buffer_get_bignum(&msg, rsa->rsa->e);
buffer_get_bignum(&msg, rsa->rsa->n);
/* host key */
(void) buffer_get_int(&msg);
buffer_get_bignum(&msg, rsa->rsa->e);
buffer_get_bignum(&msg, rsa->rsa->n);
buffer_clear(&msg);
fprintf(stdout, "%s ", output_name ? output_name : host);
key_write(rsa, stdout);
fputs("\n", stdout);
}
int
tcpconnect(char *host)
{
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr, s = -1;
snprintf(strport, sizeof strport, "%d", SSH_DEFAULT_PORT);
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
for (ai = aitop; ai; ai = ai->ai_next) {
s = socket(ai->ai_family, SOCK_STREAM, 0);
if (s < 0) {
error("socket: %s", strerror(errno));
continue;
}
if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
fatal("F_SETFL: %s", strerror(errno));
if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 &&
errno != EINPROGRESS)
error("connect (`%s'): %s", host, strerror(errno));
else
break;
close(s);
s = -1;
}
freeaddrinfo(aitop);
return s;
}
int
conalloc(char *iname, char *oname)
{
int s;
char *namebase, *name, *namelist;
namebase = namelist = xstrdup(iname);
do {
name = xstrsep(&namelist, ",");
if (!name) {
xfree(namebase);
return (-1);
}
} while ((s = tcpconnect(name)) < 0);
if (s >= maxfd)
fatal("conalloc: fdno %d too high", s);
if (fdcon[s].c_status)
fatal("conalloc: attempt to reuse fdno %d", s);
fdcon[s].c_fd = s;
fdcon[s].c_status = CS_CON;
fdcon[s].c_namebase = namebase;
fdcon[s].c_name = name;
fdcon[s].c_namelist = namelist;
fdcon[s].c_output_name = xstrdup(oname);
fdcon[s].c_data = (char *) &fdcon[s].c_plen;
fdcon[s].c_len = 4;
fdcon[s].c_off = 0;
gettimeofday(&fdcon[s].c_tv, NULL);
fdcon[s].c_tv.tv_sec += timeout;
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
FD_SET(s, read_wait);
ncon++;
return (s);
}
void
confree(int s)
{
if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
fatal("confree: attempt to free bad fdno %d", s);
close(s);
xfree(fdcon[s].c_namebase);
xfree(fdcon[s].c_output_name);
if (fdcon[s].c_status == CS_KEYS)
xfree(fdcon[s].c_data);
fdcon[s].c_status = CS_UNUSED;
TAILQ_REMOVE(&tq, &fdcon[s], c_link);
FD_CLR(s, read_wait);
ncon--;
}
void
contouch(int s)
{
TAILQ_REMOVE(&tq, &fdcon[s], c_link);
gettimeofday(&fdcon[s].c_tv, NULL);
fdcon[s].c_tv.tv_sec += timeout;
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
}
int
conrecycle(int s)
{
int ret;
con *c = &fdcon[s];
char *iname, *oname;
iname = xstrdup(c->c_namelist);
oname = xstrdup(c->c_output_name);
confree(s);
ret = conalloc(iname, oname);
xfree(iname);
xfree(oname);
return (ret);
}
void
congreet(int s)
{
char buf[80], *cp;
size_t bufsiz;
int n = 0;
con *c = &fdcon[s];
bufsiz = sizeof(buf);
cp = buf;
while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n' && *cp != '\r')
cp++;
if (n < 0) {
if (errno != ECONNREFUSED)
error("read (%s): %s", c->c_name, strerror(errno));
conrecycle(s);
return;
}
if (*cp != '\n' && *cp != '\r') {
error("%s: bad greeting", c->c_name);
confree(s);
return;
}
*cp = '\0';
fprintf(stderr, "# %s %s\n", c->c_name, buf);
n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n");
if (atomicio(write, s, buf, n) != n) {
error("write (%s): %s", c->c_name, strerror(errno));
confree(s);
return;
}
c->c_status = CS_SIZE;
contouch(s);
}
void
conread(int s)
{
int n;
con *c = &fdcon[s];
if (c->c_status == CS_CON) {
congreet(s);
return;
}
n = read(s, c->c_data + c->c_off, c->c_len - c->c_off);
if (n < 0) {
error("read (%s): %s", c->c_name, strerror(errno));
confree(s);
return;
}
c->c_off += n;
if (c->c_off == c->c_len)
switch (c->c_status) {
case CS_SIZE:
c->c_plen = htonl(c->c_plen);
c->c_len = c->c_plen + 8 - (c->c_plen & 7);
c->c_off = 0;
c->c_data = xmalloc(c->c_len);
c->c_status = CS_KEYS;
break;
case CS_KEYS:
keyprint(c->c_name, c->c_output_name, c->c_data, c->c_plen);
confree(s);
return;
break;
default:
fatal("conread: invalid status %d", c->c_status);
break;
}
contouch(s);
}
void
conloop(void)
{
fd_set *r, *e;
struct timeval seltime, now;
int i;
con *c;
gettimeofday(&now, NULL);
c = tq.tqh_first;
if (c && (c->c_tv.tv_sec > now.tv_sec ||
(c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
seltime = c->c_tv;
seltime.tv_sec -= now.tv_sec;
seltime.tv_usec -= now.tv_usec;
if (seltime.tv_usec < 0) {
seltime.tv_usec += 1000000;
seltime.tv_sec--;
}
} else
seltime.tv_sec = seltime.tv_usec = 0;
r = xmalloc(read_wait_size);
memcpy(r, read_wait, read_wait_size);
e = xmalloc(read_wait_size);
memcpy(e, read_wait, read_wait_size);
while (select(maxfd, r, NULL, e, &seltime) == -1 &&
(errno == EAGAIN || errno == EINTR))
;
for (i = 0; i < maxfd; i++) {
if (FD_ISSET(i, e)) {
error("%s: exception!", fdcon[i].c_name);
confree(i);
} else if (FD_ISSET(i, r))
conread(i);
}
xfree(r);
xfree(e);
c = tq.tqh_first;
while (c && (c->c_tv.tv_sec < now.tv_sec ||
(c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
int s = c->c_fd;
c = c->c_link.tqe_next;
conrecycle(s);
}
}
char *
nexthost(int argc, char **argv)
{
static Linebuf *lb;
for (;;) {
if (!lb) {
if (argno >= argc)
return (NULL);
if (argv[argno][0] != '-')
return (argv[argno++]);
if (!strcmp(argv[argno], "--")) {
if (++argno >= argc)
return (NULL);
return (argv[argno++]);
} else if (!strncmp(argv[argno], "-f", 2)) {
char *fname;
if (argv[argno][2])
fname = &argv[argno++][2];
else if (++argno >= argc) {
error("missing filename for `-f'");
return (NULL);
} else
fname = argv[argno++];
if (!strcmp(fname, "-"))
fname = NULL;
lb = Linebuf_alloc(fname, error);
} else
error("ignoring invalid/misplaced option `%s'",
argv[argno++]);
} else {
char *line;
line = Linebuf_getline(lb);
if (line)
return (line);
Linebuf_free(lb);
lb = NULL;
}
}
}
void
usage(void)
{
fatal("usage: %s [-t timeout] { [--] host | -f file } ...", __progname);
return;
}
int
main(int argc, char **argv)
{
char *host = NULL;
TAILQ_INIT(&tq);
if (argc <= argno)
usage();
if (argv[1][0] == '-' && argv[1][1] == 't') {
argno++;
if (argv[1][2])
timeout = atoi(&argv[1][2]);
else {
if (argno >= argc)
usage();
timeout = atoi(argv[argno++]);
}
if (timeout <= 0)
usage();
}
if (argc <= argno)
usage();
maxfd = fdlim_get(1);
if (maxfd < 0)
fatal("%s: fdlim_get: bad value", __progname);
if (maxfd > MAXMAXFD)
maxfd = MAXMAXFD;
if (MAXCON <= 0)
fatal("%s: not enough file descriptors", __progname);
if (maxfd > fdlim_get(0))
fdlim_set(maxfd);
fdcon = xmalloc(maxfd * sizeof(con));
memset(fdcon, 0, maxfd * sizeof(con));
read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
read_wait = xmalloc(read_wait_size);
memset(read_wait, 0, read_wait_size);
do {
while (ncon < MAXCON) {
char *name;
host = nexthost(argc, argv);
if (host == NULL)
break;
name = strnnsep(&host, " \t\n");
conalloc(name, *host ? host : name);
}
conloop();
} while (host);
while (ncon > 0)
conloop();
return (0);
}

View File

@ -0,0 +1,18 @@
# $OpenBSD: Makefile,v 1.3 2001/03/03 23:59:39 markus Exp $
.PATH: ${.CURDIR}/..
PROG= ssh-keyscan
BINOWN= root
BINMODE?=555
BINDIR= /usr/bin
MAN= ssh-keyscan.1
SRCS= ssh-keyscan.c
.include <bsd.prog.mk>
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}

174
crypto/openssh/ssh-rsa.c Normal file
View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-rsa.c,v 1.8 2001/03/27 10:57:00 markus Exp $");
#include <openssl/evp.h>
#include <openssl/err.h>
#include "xmalloc.h"
#include "log.h"
#include "buffer.h"
#include "bufaux.h"
#include "key.h"
#include "ssh-rsa.h"
#include "compat.h"
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
int
ssh_rsa_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
{
const EVP_MD *evp_md;
EVP_MD_CTX md;
u_char *digest, *sig, *ret;
u_int slen, dlen, len;
int ok, nid;
Buffer b;
if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
error("ssh_rsa_sign: no RSA key");
return -1;
}
nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
return -1;
}
dlen = evp_md->md_size;
digest = xmalloc(dlen);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL);
slen = RSA_size(key->rsa);
sig = xmalloc(slen);
ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
memset(digest, 'd', dlen);
xfree(digest);
if (ok != 1) {
int ecode = ERR_get_error();
error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL));
xfree(sig);
return -1;
}
if (len < slen) {
int diff = slen - len;
debug("slen %d > len %d", slen, len);
memmove(sig + diff, sig, len);
memset(sig, 0, diff);
} else if (len > slen) {
error("ssh_rsa_sign: slen %d slen2 %d", slen, len);
xfree(sig);
return -1;
}
/* encode signature */
buffer_init(&b);
buffer_put_cstring(&b, "ssh-rsa");
buffer_put_string(&b, sig, slen);
len = buffer_len(&b);
ret = xmalloc(len);
memcpy(ret, buffer_ptr(&b), len);
buffer_free(&b);
memset(sig, 's', slen);
xfree(sig);
if (lenp != NULL)
*lenp = len;
if (sigp != NULL)
*sigp = ret;
debug2("ssh_rsa_sign: done");
return 0;
}
int
ssh_rsa_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen)
{
Buffer b;
const EVP_MD *evp_md;
EVP_MD_CTX md;
char *ktype;
u_char *sigblob, *digest;
u_int len, dlen;
int rlen, ret, nid;
if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
error("ssh_rsa_verify: no RSA key");
return -1;
}
if (BN_num_bits(key->rsa->n) < 768) {
error("ssh_rsa_verify: n too small: %d bits",
BN_num_bits(key->rsa->n));
return -1;
}
buffer_init(&b);
buffer_append(&b, (char *) signature, signaturelen);
ktype = buffer_get_string(&b, NULL);
if (strcmp("ssh-rsa", ktype) != 0) {
error("ssh_rsa_verify: cannot handle type %s", ktype);
buffer_free(&b);
xfree(ktype);
return -1;
}
xfree(ktype);
sigblob = (u_char *)buffer_get_string(&b, &len);
rlen = buffer_len(&b);
buffer_free(&b);
if(rlen != 0) {
xfree(sigblob);
error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
return -1;
}
nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
xfree(sigblob);
error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
return -1;
}
dlen = evp_md->md_size;
digest = xmalloc(dlen);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL);
ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
memset(digest, 'd', dlen);
xfree(digest);
memset(sigblob, 's', len);
xfree(sigblob);
if (ret == 0) {
int ecode = ERR_get_error();
error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL));
}
debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
return ret;
}

41
crypto/openssh/ssh-rsa.h Normal file
View File

@ -0,0 +1,41 @@
/* $OpenBSD: ssh-rsa.h,v 1.3 2001/01/29 01:58:18 niklas Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SSH_RSA_H
#define SSH_RSA_H
int
ssh_rsa_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen);
int
ssh_rsa_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen);
#endif

View File

@ -1,3 +1,5 @@
# $OpenBSD: Makefile,v 1.30 2001/04/14 16:33:20 stevesk Exp $
.PATH: ${.CURDIR}/..
PROG= ssh
@ -10,7 +12,7 @@ MAN= ssh.1
LINKS= ${BINDIR}/ssh ${BINDIR}/slogin
MLINKS= ssh.1 slogin.1
SRCS= ssh.c log-client.c readconf.c clientloop.c \
SRCS= ssh.c readconf.c clientloop.c sshtty.c \
sshconnect.c sshconnect1.c sshconnect2.c
.include <bsd.own.mk> # for AFS
@ -28,5 +30,5 @@ DPADD+= ${LIBKRBAFS}
.include <bsd.prog.mk>
LDADD+= -lutil -lz -lcrypto
DPADD+= ${LIBCRYPTO} ${LIBUTIL} ${LIBZ}
LDADD+= -lcrypto -lz
DPADD+= ${LIBCRYPTO} ${LIBZ}

Some files were not shown because too many files have changed in this diff Show More