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:
commit
3ed16d1511
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76260
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -1,3 +1,5 @@
|
||||
# $OpenBSD: Makefile.inc,v 1.13 2001/01/29 01:58:14 niklas Exp $
|
||||
|
||||
CFLAGS+= -I${.CURDIR}/..
|
||||
|
||||
CFLAGS+= -Wall
|
||||
|
@ -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.
|
||||
|
@ -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
31
crypto/openssh/atomicio.h
Normal 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
104
crypto/openssh/auth-chall.c
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
112
crypto/openssh/auth2-chall.c
Normal file
112
crypto/openssh/auth2-chall.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
38
crypto/openssh/canohost.h
Normal 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);
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
39
crypto/openssh/clientloop.h
Normal file
39
crypto/openssh/clientloop.h
Normal 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);
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 ++) {
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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 */
|
||||
|
78
crypto/openssh/groupaccess.c
Normal file
78
crypto/openssh/groupaccess.c
Normal 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;
|
||||
}
|
||||
}
|
49
crypto/openssh/groupaccess.h
Normal file
49
crypto/openssh/groupaccess.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
304
crypto/openssh/kexdh.c
Normal 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
408
crypto/openssh/kexgex.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
75
crypto/openssh/log.h
Normal 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
114
crypto/openssh/mac.c
Normal 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
28
crypto/openssh/mac.h
Normal 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);
|
@ -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;
|
||||
}
|
||||
|
@ -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
130
crypto/openssh/misc.c
Normal 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
30
crypto/openssh/misc.h
Normal 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);
|
@ -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);
|
||||
|
||||
|
@ -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 ""
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
.\"
|
||||
|
@ -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
111
crypto/openssh/pathnames.h
Normal 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"
|
@ -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
28
crypto/openssh/radix.h
Normal 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);
|
@ -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
20
crypto/openssh/readpass.h
Normal 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);
|
@ -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]);
|
||||
}
|
||||
|
@ -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_
|
||||
|
||||
|
98
crypto/openssh/scp-common.c
Normal file
98
crypto/openssh/scp-common.c
Normal 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);
|
||||
}
|
64
crypto/openssh/scp-common.h
Normal file
64
crypto/openssh/scp-common.h
Normal 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);
|
@ -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 ,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>
|
||||
|
22
crypto/openssh/serverloop.h
Normal file
22
crypto/openssh/serverloop.h
Normal 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);
|
@ -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);
|
||||
|
930
crypto/openssh/sftp-client.c
Normal file
930
crypto/openssh/sftp-client.c
Normal 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;
|
||||
}
|
||||
|
107
crypto/openssh/sftp-client.h
Normal file
107
crypto/openssh/sftp-client.h
Normal 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);
|
146
crypto/openssh/sftp-common.c
Normal file
146
crypto/openssh/sftp-common.c
Normal 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 */
|
||||
}
|
||||
|
55
crypto/openssh/sftp-common.h
Normal file
55
crypto/openssh/sftp-common.h
Normal 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
146
crypto/openssh/sftp-glob.c
Normal 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));
|
||||
}
|
32
crypto/openssh/sftp-glob.h
Normal file
32
crypto/openssh/sftp-glob.h
Normal 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
917
crypto/openssh/sftp-int.c
Normal 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
27
crypto/openssh/sftp-int.h
Normal 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);
|
@ -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
@ -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
222
crypto/openssh/sftp.1
Normal 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
271
crypto/openssh/sftp.c
Normal 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
91
crypto/openssh/sftp.h
Normal 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
|
19
crypto/openssh/sftp/Makefile
Normal file
19
crypto/openssh/sftp/Makefile
Normal 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}
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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
217
crypto/openssh/ssh-dss.c
Normal 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
41
crypto/openssh/ssh-dss.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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}
|
||||
|
104
crypto/openssh/ssh-keyscan.1
Normal file
104
crypto/openssh/ssh-keyscan.1
Normal 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>
|
625
crypto/openssh/ssh-keyscan.c
Normal file
625
crypto/openssh/ssh-keyscan.c
Normal 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);
|
||||
}
|
18
crypto/openssh/ssh-keyscan/Makefile
Normal file
18
crypto/openssh/ssh-keyscan/Makefile
Normal 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
174
crypto/openssh/ssh-rsa.c
Normal 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
41
crypto/openssh/ssh-rsa.h
Normal 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
|
@ -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
Loading…
Reference in New Issue
Block a user